diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 0a6152b912bb..7a0ef59dce74 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3, 6, 6, "final", 0 +current_version = 4, 0, 8, "final", 0 commit = False tag = False parse = (?P\d+)\,\ (?P\d+)\,\ (?P\d+)\,\ \"(?P\S+)\"\,\ (?P\d+) diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 1ddfd6e1cc5b..000000000000 --- a/.dockerignore +++ /dev/null @@ -1,44 +0,0 @@ -.git -.dockerignore -Dockerfile - -# project files -coverage/ - -dev_mode/listings -dev_mode/schemas -dev_mode/static -dev_mode/themes -dev_mode/workspaces -dev_mode/stats.json - -# Skip docs -docs/ -**/docs/source/_build - -# Skip examples -examples/ - -junit.xml - -galata -jupyterlab/geckodriver -jupyterlab/static -jupyterlab/schemas -jupyterlab/themes -jupyterlab/style.js -jupyterlab/tests/**/static -jupyterlab/tests/**/labextension - -# Remove after next release -jupyterlab/imports.css - -packages/nbconvert-css/style/ -packages/services/examples/node/config.json -packages/services/examples/browser/tmp -packages/theme-*/static - -tests/**/coverage -tests/**/.cache-loader - -**/node_modules diff --git a/.eslintignore b/.eslintignore index 713a2a5ff9f3..74d8696bbd81 100644 --- a/.eslintignore +++ b/.eslintignore @@ -17,20 +17,24 @@ dev_mode/workspaces docs/_build docs/api docs/build -examples/chrome-example-test.js +examples/example.spec.ts examples/federated/core_package/index.template.js +examples/federated/core_package/index.js +examples/federated/labextensions +galata/playwright-report jupyterlab/chrome-test.js jupyterlab/geckodriver +jupyterlab/staging/yarn.js +jupyterlab/staging/index.js +jupyterlab/staging/webpack.config.js packages/extensionmanager-extension/examples/listings packages/nbconvert-css/raw.js +packages/services/dist packages/ui-components/src/icon/iconimports.ts -packages/ui-components/storybook-static -jupyterlab/staging/yarn.js -jupyterlab/staging/index.js tsconfigdoc.json -galata/playwright-report -examples/federated/core_package/index.js -examples/federated/labextensions + +#TypeDoc +typedoc-theme/ # jetbrains IDE stuff .idea/ @@ -38,3 +42,7 @@ examples/federated/labextensions # ms IDE stuff .history/ .vscode/ + +# generated LSP interfaces +packages/lsp/src/_* +packages/lsp/schema.js diff --git a/.eslintrc.js b/.eslintrc.js index 85d3e623bee2..dc45d29e5d06 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,24 +7,46 @@ module.exports = { 'jest/globals': true }, globals: { - JSX: 'readonly' + BigInt: 'readonly', + HTMLCollectionOf: 'readonly', + JSX: 'readonly', + NodeJS: 'readonly', + RequestInit: 'readonly', + RequestInfo: 'readonly', + ScrollLogicalPosition: 'readonly' }, root: true, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', - 'prettier/@typescript-eslint', - 'plugin:react/recommended', - 'plugin:jest/recommended' + 'prettier', + 'plugin:react/recommended' ], parser: '@typescript-eslint/parser', parserOptions: { - project: 'tsconfig.eslint.json' + ecmaVersion: 'ES2018', + project: ['./tsconfig.eslint.json'] }, - plugins: ['@typescript-eslint', 'jest'], + plugins: ['@typescript-eslint'], + overrides: [ + { + files: ['packages/**/*.spec.ts', 'testutils/**/*.spec.ts'], + plugins: ['jest'], + extends: ['plugin:jest/recommended'], + rules: { + 'jest/no-conditional-expect': 'warn', + 'jest/valid-title': 'warn', + 'jest/no-standalone-expect': [ + 'error', + { + additionalTestBlockFunctions: ['it'] + } + ] + } + } + ], rules: { - '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], '@typescript-eslint/naming-convention': [ 'error', { @@ -38,7 +60,6 @@ module.exports = { ], '@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }], '@typescript-eslint/no-use-before-define': 'off', - '@typescript-eslint/camelcase': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-namespace': 'off', @@ -51,8 +72,89 @@ module.exports = { '@typescript-eslint/no-empty-interface': 'off', '@typescript-eslint/triple-slash-reference': 'warn', '@typescript-eslint/no-inferrable-types': 'off', - 'jest/no-conditional-expect': 'warn', - 'jest/valid-title': 'warn', + camelcase: [ + 'error', + { + allow: [ + '__webpack_public_path__', + '__webpack_share_scopes__', + '__webpack_init_sharing__', + '_jupyter_types_experimental', + 'allow_stdin', + 'allowed_extensions', + 'allowed_extensions_uris', + 'blocked_extensions', + 'blocked_extensions_uris', + 'bundles_extension', + 'cell_type', + 'check_update', + 'clear_output', + 'codemirror_mode', + 'comm_close', + 'comm_id', + 'comm_msg', + 'comm_open', + 'copy_from', + 'creation_date', + 'cursor_end', + 'cursor_pos', + 'cursor_start', + 'detail_level', + 'display_data', + 'display_id', + 'display_name', + 'embed_options', + 'execute_input', + 'execute_result', + 'execution_count', + 'execution_state', + 'extension_data', + 'extension_name', + 'file_extension', + 'help_links', + 'hist_access_type', + 'ids_only', + 'implementation_version', + 'installed_version', + 'is_allowed', + 'jlab_core', + 'jupyterlab_extensions', + 'jupyterlab_mime_extensions', + 'kernel_spec', + 'language_info', + 'last_modified', + 'last_update_date', + 'latest_version', + 'lineWrap_type', + 'msg_type', + 'msg_id', + 'msgid_plural', + 'nbconverter_exporter', + 'nbformat_minor', + 'orig_nbformat', + 'output_mimetype', + 'output_type', + 'outputs_hidden', + 'parent_header', + 'per_page', + 'pf_re', + 'pkg_type', + 'protocol_version', + 'pygments_lexer', + 'request_seq', + 'slide_type', + 'source_hidden', + 'shutdown_reply', + 'stop_on_error', + 'store_history', + 'target_name', + 'target_module', + 'UNSAFE_componentWillUpdate', + 'UNSAFE_componentWillReceiveProps', + 'user_expressions' + ] + } + ], 'id-match': ['error', '^[a-zA-Z_]+[a-zA-Z0-9_]*$'], // https://certitude.consulting/blog/en/invisible-backdoor/ 'no-inner-declarations': 'off', 'no-prototype-builtins': 'off', diff --git a/.eslintrc.typecheck.js b/.eslintrc.typecheck.js new file mode 100644 index 000000000000..a0890d980f06 --- /dev/null +++ b/.eslintrc.typecheck.js @@ -0,0 +1,10 @@ +module.exports = { + extends: ['.eslintrc.js'], + parserOptions: { + project: 'tsconfig.eslint.json' + }, + rules: { + '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], + 'jest/no-done-callback': 'off' + } +}; diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index bce55ccc3a2f..4d23fddb92ce 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,2 +1,8 @@ -# Run Black: https://github.com/jupyterlab/jupyterlab/pull/12282 -cde0521528481befbb81fda0be8fee77dc5455df +# Run pre-commit with black: https://github.com/jupyterlab/jupyterlab/pull/12279 +6df5e0b6e8ec740ffa2f84f198820d1968e4d74d +# Add linter rule for sorting import: https://github.com/jupyterlab/jupyterlab/pull/10344 +dbdefed9db9332381fe4104bdf53ec314451951f +# Bump linters: https://github.com/jupyterlab/jupyterlab/pull/12582 +b57ec962a7b8cda65bb89a72223f195564f8387a +# Add license header fix job: https://github.com/jupyterlab/jupyterlab/pull/12872 +1bcbf90f26bc9141681965a094c75985b758a2c9 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index d663a30ec4ed..000000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,57 +0,0 @@ -______________________________________________________________________ - -## name: Bug report about: Create a report to help us improve - - - -## Description - - - -## Reproduce - - - -1. Go to '...' -1. Click on '...' -1. Scroll down to '...' -1. See error '...' - - - -## Expected behavior - - - -## Context - - - -- Operating System and version: -- Browser and version: -- JupyterLab version: - -
Troubleshoot Output -
-Paste the output from running `jupyter troubleshoot` from the command line here.
-You may want to sanitize the paths in the output.
-
-
- -
Command Line Output -
-Paste the output from your command line running `jupyter lab` here, use `--debug` if possible.
-
-
- -
Browser Output -
-Paste the output from your browser Javascript console here.
-
-
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 343465d11c05..000000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,32 +0,0 @@ -______________________________________________________________________ - -## name: Feature Request about: Suggest something to add to JupyterLab labels: enhancement - - - -### Problem - - - -### Proposed Solution - - - -### Additional context - - diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 635a80d851dd..428c924883de 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -12,6 +12,3 @@ paths-ignore: - examples/federated/core_package/index.js - jupyterlab/staging/index.js - dev_mode/index.js - # TODO: remove when fixed upstream - # see https://github.com/jupyterlab/jupyterlab/issues/10522 for more info - - packages/services/src/kernel/messages.ts diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..a34b92fc05ae --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +version: 2 +updates: + # Set update schedule for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every month + interval: "monthly" + # Set update schedule for pip + - package-ecosystem: "pip" + directory: "/" + schedule: + # Check for updates to GitHub Actions every month + # Align with pre-commit configuration .pre-commit-config.yaml + interval: "monthly" diff --git a/.github/jupyterlab-probot.yml b/.github/jupyterlab-probot.yml new file mode 100644 index 000000000000..3703b3e3da87 --- /dev/null +++ b/.github/jupyterlab-probot.yml @@ -0,0 +1,3 @@ +binderUrlSuffix: "?urlpath=lab" +addBinderLink: true +triageLabel: "status:Needs Triage" diff --git a/.github/labeler.yml b/.github/labeler.yml index 2bce9ba890c2..ddadd9e99d4b 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -5,6 +5,8 @@ Design System CSS: documentation: - docs/**/* - docs/* + - '*.md' + - '**/*.md' tag:CSS: - '**/*.css' @@ -55,8 +57,6 @@ pkg:cells: - packages/cells/* pkg:celltags: - - packages/celltags/**/* - - packages/celltags/* - packages/celltags-extension/**/* - packages/celltags-extension/* @@ -64,12 +64,6 @@ pkg:codeeditor: - packages/codeeditor/**/* - packages/codeeditor/* -pkg:collaboration: - - packages/collaboration/**/* - - packages/collaboration/* - - packages/collaboration-extension/**/* - - packages/collaboration-extension/* - pkg:codemirror: - packages/codemirror/**/* - packages/codemirror/* @@ -110,12 +104,6 @@ pkg:docmanager: - packages/docmanager-extension/**/* - packages/docmanager-extension/* -pkg:docprovider: - - packages/docprovider/**/* - - packages/docprovider/* - - packages/docprovider-extension/**/* - - packages/docprovider-extension/* - pkg:docregistry: - packages/docregistry/**/* - packages/docregistry/* @@ -190,6 +178,12 @@ pkg:logconsole: - packages/logconsole-extension/**/* - packages/logconsole-extension/* +pkg:lsp: + - packages/lsp/**/* + - packages/lsp/* + - packages/lsp-extension/**/* + - packages/lsp-extension/* + pkg:mainmenu: - packages/mainmenu/**/* - packages/mainmenu/* @@ -202,11 +196,9 @@ pkg:markdownviewer: - packages/markdownviewer-extension/**/* - packages/markdownviewer-extension/* -pkg:mathjax2: - - packages/mathjax2/**/* - - packages/mathjax2/* - - packages/mathjax2-extension/**/* - - packages/mathjax2-extension/* +pkg:mathjax: + - packages/mathjax-extension/**/* + - packages/mathjax-extension/* pkg:notebook: - packages/notebook/**/* @@ -308,12 +300,6 @@ pkg:ui-components: - packages/ui-components-extension/**/* - packages/ui-components-extension/* -pkg:vdom: - - packages/vdom/**/* - - packages/vdom/* - - packages/vdom-extension/**/* - - packages/vdom-extension/* - pkg:vega: - packages/vega5-extension/**/* - packages/vega5-extension/* diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 23de33d09d39..d7c2c2df8a4d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,31 +1,26 @@ -## Jira ticket + -https://spotinst.atlassian.net/browse/BGD-XXXX +## References -## Checklist -- [ ] I added a Jira ticket link -- [ ] I added a changeset with the `simple-changeset add` command -- [ ] I filled in the test plan -- [ ] I executed the tests and filled in the test results + -## Why + -_A short description of why this change is necessary. If this is a bug fix, include steps to reproduce the issue_ +## Code changes -## What + -_What has been modified. Expose the key decisions you have made during this PR to facilitate the discussion with your reviewer_ +## User-facing changes -## How to test + -_Step by step instructions to test your feature/fix_ + -## Test plan and results +## Backwards-incompatible changes -_Feel free to add screenshots showing test results_ - -| Test | Description | Result | Notes | -|------|-------------------|--------|----------------------------| -| 1 | Test with input A | Pass | Some notes about the test | -| 2 | Test with input B | Pass | Some notes about the test | -| 3 | Test with input C | Pass | Some notes about the test | + diff --git a/.github/workflows/answered.yml b/.github/workflows/answered.yml new file mode 100644 index 000000000000..99326d98194b --- /dev/null +++ b/.github/workflows/answered.yml @@ -0,0 +1,24 @@ +# This action automatically schedules issues to be closed that have been +# labeled as answered if there is no activity on them for 30 days. This takes +# care of the common usecase of an issue being answered to the best of our +# ability and no other follow-up from the submitter. +name: 'Close answered issues' +on: + schedule: + - cron: '30 1 * * *' + +permissions: + issues: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + days-before-pr-stale: -1 + days-before-pr-close: -1 + days-before-issue-stale: 7 + days-before-issue-close: 5 + stale-issue-label: 'status:Closing as Answered' + only-issue-labels: 'status:Answered' diff --git a/.github/workflows/auto_author_assign.yml b/.github/workflows/auto_author_assign.yml new file mode 100644 index 000000000000..046a6a71bfed --- /dev/null +++ b/.github/workflows/auto_author_assign.yml @@ -0,0 +1,15 @@ +# https://github.com/marketplace/actions/auto-author-assign +name: 'Auto Author Assign' + +on: + pull_request_target: + types: [opened, reopened] + +permissions: + pull-requests: write + +jobs: + assign-author: + runs-on: ubuntu-latest + steps: + - uses: toshimaru/auto-author-assign@v1.6.2 diff --git a/.github/workflows/benchmark-report.yml b/.github/workflows/benchmark-report.yml new file mode 100644 index 000000000000..01319563276c --- /dev/null +++ b/.github/workflows/benchmark-report.yml @@ -0,0 +1,83 @@ +# Commenting on a PR requires write access +# but PR opened from forks does not get write access +# except when triggered with `pull_request_target` +# +# So the comments payload must be created from a `pull_request` event workflow. +# Then that payload can be posted as PR comment in a `pull_request_target` event workflow. +# +# Documentation: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request_target +# Blog post with example: https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ + +name: Comment on the pull request + +on: + workflow_run: + workflows: ['Benchmark Tests'] + types: + - completed + +permissions: + pull-requests: write + +jobs: + upload: + runs-on: ubuntu-latest + # Carry action even on failure (happening if memory leak tests fail for example) + if: github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure' + steps: + - name: 'Download artifact' + uses: actions/github-script@v6 + with: + script: | + var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{ github.event.workflow_run.id }}, + }); + var matchArtifact = artifacts.data.artifacts.filter((artifact) => { + return artifact.name == "benchmark-assets" + })[0]; + var download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + var fs = require('fs'); + fs.writeFileSync('${{ github.workspace }}/benchmark-assets.zip', Buffer.from(download.data)); + - run: unzip benchmark-assets.zip + + - name: 'Comment on PR' + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + var fs = require('fs'); + var issue_number = Number(fs.readFileSync('./benchmark-results/NR')); + var report = String(fs.readFileSync('./benchmark-results/lab-benchmark.md')); + var memory_report = String(fs.readFileSync('./memory-leak-report.md')); + + // Get the existing comments. + const {data: comments} = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue_number, + }) + + // Find any comment already made by the bot. + const botComment = comments.find(comment => comment.user.id === 41898282) + if (botComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: [report, memory_report].join('\n') + }) + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue_number, + body: [report, memory_report].join('\n') + }); + } diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 000000000000..bee96c204ea5 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,259 @@ +name: Benchmark Tests + +on: + # schedule: + # - cron: '12 1 * * 0' + pull_request_review: + +jobs: + test: + name: Execute benchmark tests + if: github.event_name == 'schedule' || (github.event_name == 'pull_request_review' && (github.event.review.state == 'approved' || contains(github.event.review.body, 'please run benchmark'))) + + runs-on: ubuntu-22.04 + + env: + BENCHMARK_NUMBER_SAMPLES: 100 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Need to fetch enough nodes to get the common ancestor - but don't want to fetch everything + fetch-depth: 100 + + - name: Get hashes for schedule event + if: ${{ github.event_name == 'schedule' }} + run: | + echo "OLD_REF_SHA=$(git rev-parse 'main@{7 days ago}')" >> $GITHUB_ENV + echo "NEW_REF_SHA=$(git rev-parse 'main')" >> $GITHUB_ENV + + - name: Get hashes for PR review event + if: ${{ github.event_name == 'pull_request_review' }} + uses: actions/github-script@v6 + with: + script: | + const child_process = require("child_process"); + const pull_request = context.payload.pull_request; + + child_process.exec(`git merge-base ${pull_request.head.sha} ${pull_request.base.sha}`, (error, stdout, stderr) => { + if (error) { + console.log(error); + process.exit(1); + return; + } + if (stderr) { + console.log(stderr); + process.exit(1); + return; + } + + core.exportVariable('OLD_REF_SHA', stdout.trim()); + core.exportVariable('NEW_REF_SHA', pull_request.head.sha); + core.exportVariable('PULL_REQUEST_ID', pull_request.number); + }); + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - uses: iterative/setup-cml@v2 + + # First run the benchmark on the old reference + - name: Checkout old reference + run: | + echo Checking out ${OLD_REF_SHA}... + git checkout ${OLD_REF_SHA} + + - name: Install dependencies + run: | + bash ./scripts/ci_install.sh + # Build dev-mode + jlpm run build + + - name: Launch JupyterLab + shell: bash + run: | + # Mount a volume to overwrite the server configuration + (jlpm start > /tmp/jupyterlab_server_old.log 2>&1) & + working-directory: galata + + - name: Install browser + run: | + # Install only Chromium browser + jlpm playwright install chromium + jlpm run build + working-directory: galata + + - name: Wait for JupyterLab + uses: ifaxity/wait-on-action@v1 + with: + resource: http-get://localhost:8888/lab + timeout: 360000 + + - name: Execute benchmark tests + continue-on-error: true + working-directory: galata + run: | + jlpm run test:benchmark -u + + - name: Kill the server + shell: bash + run: | + kill -s SIGKILL $(pgrep jupyter-lab) + + # Second run the benchmark on the new reference + - name: Checkout latest version + run: | + cp galata/lab-benchmark-expected.json /tmp/ + git restore galata/lab-benchmark-expected.json || true # Not versioned any more + echo Checking out ${NEW_REF_SHA}... + git checkout ${NEW_REF_SHA} + + - name: Install dependencies + run: | + # Reset installation + jlpm run clean:slate + jlpm run build + + - name: Launch JupyterLab + working-directory: galata + run: | + # Mount a volume to overwrite the server configuration + (jlpm start > /tmp/jupyterlab_server_new.log 2>&1) & + + - name: Install browser + working-directory: galata + run: | + # Install only Chromium browser + jlpm playwright install chromium + jlpm run build + + - name: Wait for JupyterLab + uses: ifaxity/wait-on-action@v1 + with: + resource: http-get://localhost:8888/lab + timeout: 360000 + + - name: Execute benchmark tests + continue-on-error: true + shell: bash + working-directory: galata + run: | + set -ex + # Update test screenshots - in case they have not yet been corrected on the challenger branch + BENCHMARK_NUMBER_SAMPLES=1 PW_VIDEO=1 jlpm run test:benchmark -u + + # Copy reference here otherwise it will use the value from the update screenshots + # command called just before + cp /tmp/lab-benchmark-expected.json . + + jlpm run test:benchmark + + - name: Stop JupyterLab + if: always() + run: | + kill -s SIGTERM $(pgrep jupyter-lab) + + - name: Generate the report + env: + REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPORT: ./benchmark-results/lab-benchmark.md + shell: bash + working-directory: galata + run: | + # Publish image to cml.dev + echo "" >> ${REPORT} + cml-publish ./benchmark-results/lab-benchmark.svg --md >> ${REPORT} + echo "" >> ${REPORT} + + # Test if metadata have changed + export METADATA_DIFF="/tmp/metadata.diff" + diff -u <(jq --sort-keys .metadata benchmark-results/lab-benchmark.json) <(jq --sort-keys .metadata lab-benchmark-expected.json) > ${METADATA_DIFF} || true + if [[ -s ${METADATA_DIFF} ]]; then + echo "
:exclamation: Test metadata have changed" >> ${REPORT} + echo "" >> ${REPORT} + echo "\`\`\`diff" >> ${REPORT} + cat ${METADATA_DIFF} >> ${REPORT} + echo "\`\`\`" >> ${REPORT} + echo "" >> ${REPORT} + echo "
" >> ${REPORT} + fi + + # Set the report as summary + cat ${REPORT} >> ${GITHUB_STEP_SUMMARY} + + # Copy the reference data to upload it as artifact + cp lab-benchmark-expected.json ./benchmark-results/ + + # Save PR number for comment publication + echo "${PULL_REQUEST_ID}" > ./benchmark-results/NR + + - name: Upload Galata Test assets + if: always() + uses: actions/upload-artifact@v3 + with: + name: benchmark-assets + path: | + galata/benchmark-results + galata/test-results + + - name: Print JupyterLab logs + if: always() + run: | + cat /tmp/jupyterlab_server_old.log + cat /tmp/jupyterlab_server_new.log + + memory-leak: + name: Execute memory-leak tests + if: github.event_name == 'schedule' || (github.event_name == 'pull_request_review' && (github.event.review.state == 'approved' || contains(github.event.review.body, 'please run benchmark'))) + + runs-on: ubuntu-22.04 + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get hashes for PR review event + if: ${{ github.event_name == 'pull_request_review' }} + uses: actions/github-script@v6 + with: + script: | + const child_process = require("child_process"); + const pull_request = context.payload.pull_request; + core.exportVariable('PULL_REQUEST_ID', pull_request.number); + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Install dependencies + run: | + bash ./scripts/ci_install.sh + # Build dev-mode + jlpm run build + + - name: Launch JupyterLab + shell: bash + run: | + # Mount a volume to overwrite the server configuration + jlpm start > /tmp/jupyterlab_server.log 2>&1 & + working-directory: galata + + - name: Execute memory leak tests + id: memory_leaks + uses: jupyterlab/benchmarks/.github/actions/memory-leak@v1 + with: + server_url: localhost:8888 + artifacts_name: benchmark-assets + + - name: Kill the server + if: always() + shell: bash + run: | + kill -s SIGKILL $(pgrep jupyter-lab) + + - name: Print JupyterLab logs + if: always() + shell: bash + run: | + cat /tmp/jupyterlab_server.log diff --git a/.github/workflows/check-i18n.yml b/.github/workflows/check-i18n.yml new file mode 100644 index 000000000000..82078c88f6ee --- /dev/null +++ b/.github/workflows/check-i18n.yml @@ -0,0 +1,48 @@ +name: Check internationalization changes + +on: + pull_request: + +jobs: + check_i18n: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Install dependencies + run: | + python -m pip install -U pip jupyterlab-translate~=1.0 + + - name: Compute hash + id: currentHash + run: | + set -eux + HASH=$(python scripts/i18n_check.py | tail -n1) + echo "::set-output name=i18n::${HASH}" + + - name: Checkout target + run: | + echo Checking ${GITHUB_BASE_REF}... + # Ref https://github.com/actions/checkout/issues/93 + git fetch --depth=1 origin +refs/heads/${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF} + git checkout ${GITHUB_BASE_REF} + + - name: Check hash + env: + CURRENT: ${{ steps.currentHash.outputs.i18n }} + run: | + set -eux + EXPECTED=$(python scripts/i18n_check.py | tail -n1) + if [[ "${CURRENT}" != "${EXPECTED}" ]]; then + echo "Translatable strings have changed, this is only allowed on major or minor version bumps." + # Set job status as failed if + # - branch is not "main" + # - and current version is not a pre release of a zeroed patch version + if [[ "${GITHUB_BASE_REF}" != "main" && ! ( $(python setup.py --version) =~ ^[0-9]+\.[0-9]+\.0(\.dev|a|b|rc)[0-9]+$ ) ]]; then + exit 1 + fi + fi diff --git a/.github/workflows/check-release.yml b/.github/workflows/check-release.yml new file mode 100644 index 000000000000..5fa2eca991cd --- /dev/null +++ b/.github/workflows/check-release.yml @@ -0,0 +1,33 @@ +name: Check Release + +on: + push: + branches: [4.0.x] + pull_request: + branches: [4.0.x] + release: + types: [published] + +jobs: + + check_release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Check Release + uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version_spec: next + + - name: Upload Assets + uses: actions/upload-artifact@v3 + with: + name: jupyterlab-releaser-dist-${{ github.run_number }} + path: | + .jupyter_releaser_checkout/dist/*.* diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index bcc2b5764256..b6aa4521fd06 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -7,10 +7,10 @@ name: "CodeQL" on: push: - branches: [3.6.x] + branches: [4.0.x] pull_request: # The branches below must be a subset of the branches above - branches: [3.6.x] + branches: [4.0.x] schedule: - cron: '0 8 * * 3' @@ -21,7 +21,7 @@ permissions: jobs: analyze: name: Analyze - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: fail-fast: false @@ -34,7 +34,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -42,7 +42,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -55,7 +55,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -69,4 +69,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/enforce-label.yml b/.github/workflows/enforce-label.yml new file mode 100644 index 000000000000..79b6f0eab6c4 --- /dev/null +++ b/.github/workflows/enforce-label.yml @@ -0,0 +1,13 @@ +name: Enforce PR label + +on: + pull_request_target: + types: [labeled, unlabeled, opened, edited, synchronize] +jobs: + enforce-label: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: enforce-triage-label + uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1 diff --git a/.github/workflows/galata-update.yml b/.github/workflows/galata-update.yml new file mode 100644 index 000000000000..1c8b5afbbe83 --- /dev/null +++ b/.github/workflows/galata-update.yml @@ -0,0 +1,140 @@ +name: Update Playwright Snapshots + +on: + issue_comment: + types: [created, edited] + +permissions: + contents: write + pull-requests: write + +jobs: + update-galata-snapshots: + name: Update Galata References + if: ${{ github.event.issue.pull_request && (contains(github.event.comment.body, 'please update galata snapshots') || contains(github.event.comment.body, 'please update snapshots')) }} + timeout-minutes: 80 + runs-on: ubuntu-22.04 + + steps: + - name: React to the triggering comment + run: | + gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions --raw-field 'content=+1' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure git to use https + run: git config --global hub.protocol https + + - name: Checkout the branch from the PR that triggered the job + run: gh pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Install dependencies + run: | + bash ./scripts/ci_install.sh + # Build dev-mode + jlpm run build + + - uses: jupyterlab/maintainer-tools/.github/actions/update-snapshots@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + server_url: http-get://localhost:8888/lab + test_folder: galata + artifact_name: updated-galata-snapshots + report_name: update-galata-report + + - name: Comment back on the PR + run: | + gh api repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments --raw-field 'body=Galata snapshots updated.' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + update-documentation-snapshots: + name: Update Documentation Snapshots + if: ${{ github.event.issue.pull_request && (contains(github.event.comment.body, 'please update documentation snapshots') || contains(github.event.comment.body, 'please update snapshots')) }} + timeout-minutes: 80 + runs-on: ubuntu-22.04 + + # Python version is frozen through strategy.matrix.python-version + # Python dependencies are frozen in the installation step + # Note: IPython is among the frozen package + strategy: + matrix: + # Freeze Python version because it appears in console header + python-version: ['3.10.6'] + + steps: + - name: React to the triggering comment + run: | + gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions --raw-field 'content=+1' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout JupyterLab + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + path: core + + - name: Checkout demo project + uses: actions/checkout@v4 + with: + repository: jupyterlab/jupyterlab-demo + ref: master + path: demo + + - name: Get demo folder + run: | + echo "JUPYTERLAB_GALATA_ROOT_DIR=$PWD" >> $GITHUB_ENV + working-directory: demo + + - name: Checkout the branch from the PR that triggered the job + working-directory: core + run: gh pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Install dependencies + working-directory: core + run: | + set -ex + # Install chinese font + sudo apt-get update + sudo apt-get install fonts-dejavu fonts-noto + + # Freeze the packages to ensure consistent look and feel + # IPython is frozen because its version is displayed in + # the console header + pip install .[docs-screenshots] + bash ./scripts/ci_install.sh + + # Build dev-mode + jlpm run build + + - uses: jupyterlab/maintainer-tools/.github/actions/update-snapshots@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + server_url: http-get://localhost:8888/lab + test_folder: core/galata + start_server_script: start:doc + update_script: test:doc:update + artifact_name: updated-documentation-snapshots + report_name: update-documentation-report + + - name: Comment back on the PR + run: | + gh api repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments --raw-field 'body=Documentation snapshots updated.' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/galata.yml b/.github/workflows/galata.yml new file mode 100644 index 000000000000..69b7223d8312 --- /dev/null +++ b/.github/workflows/galata.yml @@ -0,0 +1,201 @@ +name: UI Tests + +on: + issue_comment: + types: [created] + push: + branches: + - main + pull_request: + +env: + PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/pw-browsers + +jobs: + test: + name: Visual Regression Tests + if: ${{ (github.event_name != 'issue_comment') || (github.event.issue.pull_request && (contains(github.event.comment.body, 'Galata snapshots updated.'))) }} + timeout-minutes: 80 + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Set up browser cache + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/pw-browsers + key: ${{ runner.os }}-${{ hashFiles('ui-tests/yarn.lock') }} + + - name: Install dependencies + run: | + bash ./scripts/ci_install.sh + # Build dev-mode + jlpm run build + + - name: Launch JupyterLab + run: | + cd galata + jlpm start 2>&1 > /tmp/jupyterlab_server.log & + + - name: Install browser + run: | + cd galata + # Install only Chromium browser + jlpm playwright install chromium + jlpm run build + + - name: Wait for JupyterLab + uses: ifaxity/wait-on-action@v1 + with: + resource: http-get://localhost:8888/lab + timeout: 360000 + + - name: Test + run: | + cd galata + jlpm run test --project galata jupyterlab + mv galata/test-results galata/test-jupyterlab-results || true + # Run once benchmark tests to ensure they have no regression + BENCHMARK_NUMBER_SAMPLES=1 jlpm run test:benchmark + + - name: Upload Galata Test assets + if: always() + uses: actions/upload-artifact@v3 + with: + name: jupyterlab-galata-test-assets + path: | + galata/test-jupyterlab-results + galata/test-results + + - name: Upload Galata Test report + if: always() + uses: actions/upload-artifact@v3 + with: + name: jupyterlab-galata-report + path: | + galata/playwright-report + + - name: Print JupyterLab logs + if: always() + run: | + cat /tmp/jupyterlab_server.log + + test-documentation: + name: Visual Regression Documentation + if: ${{ (github.event_name != 'issue_comment') || (github.event.issue.pull_request && (contains(github.event.comment.body, 'Documentation snapshots updated.'))) }} + # Python version is frozen through strategy.matrix.python-version + # Python dependencies are frozen in the installation step + # Note: IPython is among the frozen package + timeout-minutes: 80 + runs-on: ubuntu-22.04 + strategy: + matrix: + # Freeze Python version because it appears in console header + python-version: ['3.10.6'] + steps: + - name: Checkout JupyterLab + uses: actions/checkout@v4 + with: + path: core + + - name: Checkout demo project + uses: actions/checkout@v4 + with: + repository: jupyterlab/jupyterlab-demo + ref: master + path: demo + + - name: Get demo folder + run: | + echo "DEMO_DIR=$PWD" >> $GITHUB_ENV + working-directory: demo + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Set up browser cache + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/pw-browsers + key: ${{ runner.os }}-${{ hashFiles('ui-tests/yarn.lock') }} + + - name: Install dependencies + run: | + set -ex + # Install chinese font + sudo apt-get update + sudo apt-get install fonts-dejavu fonts-noto + + # Freeze the packages to ensure consistent look and feel + # IPython is frozen because its version is displayed in + # the console header + pip install .[docs-screenshots] + bash ./scripts/ci_install.sh + + # Build dev-mode + jlpm run build + working-directory: core + + - name: Launch JupyterLab + env: + JUPYTERLAB_GALATA_ROOT_DIR: ${{ env.DEMO_DIR }} + # Ignore Python warning for cleaner documentation snapshots + PYTHONWARNINGS: ignore + run: | + set -ex + cd galata + (jupyter lab --config jupyter_server_test_config.py --extensions-in-dev-mode > /tmp/jupyterlab_server.log 2>&1) & + working-directory: core + + - name: Install browser + run: | + set -ex + cd galata + # Install only Chromium browser + jlpm playwright install chromium + jlpm run build + working-directory: core + + - name: Wait for JupyterLab + uses: ifaxity/wait-on-action@v1 + with: + resource: http-get://localhost:8888/lab + timeout: 360000 + + - name: Test + run: | + cd galata + jlpm run test:doc + working-directory: core + + - name: Upload Galata Test assets + if: always() + uses: actions/upload-artifact@v3 + with: + name: jupyterlab-documentation-test-assets + path: | + core/galata/test-results + + - name: Upload Galata Test report + if: always() + uses: actions/upload-artifact@v3 + with: + name: jupyterlab-documentation-report + path: | + core/galata/playwright-report + + - name: Stop JupyterLab + if: always() + run: | + kill -s SIGTERM $(pgrep jupyter-lab) + + - name: Print JupyterLab logs + if: always() + run: | + cat /tmp/jupyterlab_server.log diff --git a/.github/workflows/license-header.yml b/.github/workflows/license-header.yml new file mode 100644 index 000000000000..74806f5ce6fd --- /dev/null +++ b/.github/workflows/license-header.yml @@ -0,0 +1,60 @@ +name: Fix License Headers + +on: + pull_request_target: + +jobs: + header-license-fix: + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure git to use https + run: git config --global hub.protocol https + + - name: Checkout the branch from the PR that triggered the job + run: gh pr checkout ${{ github.event.pull_request.number }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Fix License Header + uses: apache/skywalking-eyes/header@v0.4.0 + with: + mode: fix + + - name: List files changed + id: files-changed + shell: bash -l {0} + run: | + set -ex + export CHANGES=$(git status --porcelain | tee /tmp/modified.log | wc -l) + cat /tmp/modified.log + + echo "N_CHANGES=${CHANGES}" >> $GITHUB_OUTPUT + + git diff + + - name: Commit any changes + if: steps.files-changed.outputs.N_CHANGES != '0' + shell: bash -l {0} + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git pull --no-tags + + git add * + git commit -m "Automatic application of license header" + + git config push.default upstream + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/linuxjs-flaky-tests.yml b/.github/workflows/linuxjs-flaky-tests.yml deleted file mode 100644 index 3d7cf12226cb..000000000000 --- a/.github/workflows/linuxjs-flaky-tests.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Linux JS Flaky Tests - -on: - push: - branches: [3.6.x] - pull_request: - branches: [3.6.x] - release: - types: [published] - -jobs: - linuxjs: - name: JS - strategy: - matrix: - group: [js-apputils, js-services] - fail-fast: false - runs-on: ubuntu-20.04 - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Base Setup - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - - - name: Install dependencies - env: - GROUP: ${{ matrix.group }} - run: | - bash ./scripts/ci_install.sh - - - name: Run test ${{ matrix.group }} - env: - GROUP: ${{ matrix.group }} - run: | - bash ./scripts/ci_script.sh diff --git a/.github/workflows/linuxjs-tests.yml b/.github/workflows/linuxjs-tests.yml index 20d4b9c6aba0..10a1b992ea91 100644 --- a/.github/workflows/linuxjs-tests.yml +++ b/.github/workflows/linuxjs-tests.yml @@ -2,9 +2,9 @@ name: Linux JS Tests on: push: - branches: [3.6.x] + branches: [4.0.x] pull_request: - branches: [3.6.x] + branches: [4.0.x] release: types: [published] @@ -20,8 +20,9 @@ jobs: group: [ js-application, - js-cells, + js-apputils, js-cell-toolbar, + js-cells, js-codeeditor, js-codemirror, js-completer, @@ -37,28 +38,33 @@ jobs: js-imageviewer, js-inspector, js-logconsole, + js-lsp, js-mainmenu, + js-metadataform, + js-metapackage, js-nbformat, js-notebook, js-observables, js-outputarea, js-rendermime, + js-services, + js-settingeditor, js-settingregistry, js-statedb, js-statusbar, + js-testing, js-terminal, js-toc, js-translation, js-ui-components, js-vega5-extension, - js-testutils, ] fail-fast: false - runs-on: ubuntu-20.04 - timeout-minutes: 20 + runs-on: ubuntu-22.04 + timeout-minutes: 40 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 diff --git a/.github/workflows/linuxtests.yml b/.github/workflows/linuxtests.yml index 07fcc0b325cb..ac55d70fea84 100644 --- a/.github/workflows/linuxtests.yml +++ b/.github/workflows/linuxtests.yml @@ -2,9 +2,9 @@ name: Linux Tests on: push: - branches: [3.6.x] + branches: [4.0.x] pull_request: - branches: [3.6.x] + branches: [4.0.x] release: types: [published] @@ -13,59 +13,43 @@ jobs: name: Linux strategy: matrix: - group: - [ - integrity, - integrity2, - integrity3, - release_test, - docs, - usage, - usage2, - splice_source, - python, - examples, - interop, - nonode, - linkcheck, - lint, - ] + group: [integrity, integrity2, integrity3, release_test, docs, usage, usage2, splice_source, python, examples, interop, nonode, lint] # This will be used by the base setup action - python-version: ['3.7', '3.10'] + python-version: ["3.8", "3.11"] include: + - group: examples + upload-output: true - group: release_test upload-output: true exclude: - group: integrity - python-version: '3.7' + python-version: "3.8" - group: integrity2 - python-version: '3.7' + python-version: "3.8" - group: integrity3 - python-version: '3.7' + python-version: "3.8" - group: release_test - python-version: '3.7' + python-version: "3.8" - group: docs - python-version: '3.7' + python-version: "3.8" - group: usage - python-version: '3.7' + python-version: "3.8" - group: usage2 - python-version: '3.7' - - group: linkcheck - python-version: '3.7' + python-version: "3.8" - group: nonode - python-version: '3.7' + python-version: "3.8" - group: lint - python-version: '3.7' + python-version: "3.8" - group: examples - python-version: '3.7' + python-version: "3.8" - group: splice_source - python-version: '3.7' + python-version: "3.8" fail-fast: false timeout-minutes: 45 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 @@ -88,17 +72,37 @@ jobs: - name: Upload ${{ matrix.group }} results if: ${{ matrix.upload-output && always() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ matrix.group }} ${{ github.run_number }} - path: ./build/${{ matrix.group }}_output + path: | + ./build/${{ matrix.group }}_output + ./examples/*/test-results + + test_minimum_versions: + name: Test Minimum Versions + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + with: + python_version: "3.8" + - name: Install minimum versions + uses: jupyterlab/maintainer-tools/.github/actions/install-minimums@v1 + - name: Install dependencies + run: | + bash ./scripts/ci_install.sh + - name: Run the unit tests + run: pytest -vv || pytest -vv --lf make_sdist: name: Make SDist runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Install dependencies @@ -108,7 +112,7 @@ jobs: run: | pip install build python -m build --sdist - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: "sdist" path: dist/*.tar.gz @@ -122,7 +126,7 @@ jobs: - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Download sdist - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 - name: Install From SDist run: | set -ex @@ -130,7 +134,7 @@ jobs: mkdir test tar --strip-components=1 -zxvf *.tar.gz -C ./test cd test - pip install -e .[test] + pip install -e .[dev,test] pip install pytest-github-actions-annotate-failures - name: Run Test run: | @@ -139,11 +143,15 @@ jobs: check_links: runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 30 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + - run: | + node ./jupyterlab/staging/yarn.js install + node ./jupyterlab/staging/yarn.js run build:packages + node ./jupyterlab/staging/yarn.js run docs - uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1 with: - ignore_glob: "packages/ui-components/docs/source/ui_components.rst images" - ignore_links: "../api/*.* .*/images/[\\w-]+.png https://docs.github.com/en/.* https://blog.jupyter.org/jupyterlab-is-ready-for-users-5a6f039b8906 https://jupyterlab.github.io https://registry.npmjs.org/.* https://mybinder.org/v2/gh/jupyterlab/.*" + ignore_glob: "docs/api packages/ui-components/docs/source/ui_components.rst images" + ignore_links: ".*/images/[\\w-]+.png https://docs.github.com/en/.* https://jupyterlab.github.io https://mybinder.org/v2/gh/jupyterlab/.*" diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml new file mode 100644 index 000000000000..e84180046f75 --- /dev/null +++ b/.github/workflows/lock.yml @@ -0,0 +1,23 @@ +name: 'Lock Closed Threads' + +on: + schedule: + - cron: '0 0 * * *' + +permissions: + issues: + write + pull-requests: + write + +jobs: + lock: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v4 + with: + github-token: ${{ github.token }} + issue-lock-inactive-days: '180' + issue-lock-labels: 'status:resolved-locked' + pr-lock-inactive-days: '180' + pr-lock-labels: 'status:resolved-locked' diff --git a/.github/workflows/macostests.yml b/.github/workflows/macostests.yml index e76349b8bb27..c7e060644ed2 100644 --- a/.github/workflows/macostests.yml +++ b/.github/workflows/macostests.yml @@ -2,9 +2,9 @@ name: macOS Tests on: push: - branches: [3.6.x] + branches: [4.0.x] pull_request: - branches: [3.6.x] + branches: [4.0.x] release: types: [published] @@ -14,13 +14,13 @@ jobs: strategy: matrix: group: [integrity, python, usage, usage2] - python: [3.8] + python-version: [3.11] fail-fast: false timeout-minutes: 45 runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 diff --git a/.github/workflows/prep-release.yml b/.github/workflows/prep-release.yml new file mode 100644 index 000000000000..7a2a18de7570 --- /dev/null +++ b/.github/workflows/prep-release.yml @@ -0,0 +1,42 @@ +name: "Step 1: Prep Release" +on: + workflow_dispatch: + inputs: + version_spec: + description: "New Version Specifier" + default: "next" + required: false + branch: + description: "The branch to target" + required: false + post_version_spec: + description: "Post Version Specifier" + required: false + since: + description: "Use PRs with activity since this date or git reference" + required: false + since_last_stable: + description: "Use PRs with activity since the last stable git tag" + required: false + type: boolean +jobs: + prep_release: + runs-on: ubuntu-latest + steps: + - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Prep Release + id: prep-release + uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2 + with: + token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + version_spec: ${{ github.event.inputs.version_spec }} + post_version_spec: ${{ github.event.inputs.post_version_spec }} + target: ${{ github.event.inputs.target }} + branch: ${{ github.event.inputs.branch }} + since: ${{ github.event.inputs.since }} + since_last_stable: ${{ github.event.inputs.since_last_stable }} + + - name: "** Next Step **" + run: | + echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}" diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 000000000000..dbaaeaad243b --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,54 @@ +name: "Step 2: Publish Release" +on: + workflow_dispatch: + inputs: + branch: + description: "The target branch" + required: false + release_url: + description: "The URL of the draft GitHub release" + required: false + steps_to_skip: + description: "Comma separated list of steps to skip" + required: false + +jobs: + publish_release: + runs-on: ubuntu-latest + steps: + - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Populate Release + id: populate-release + uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2 + with: + token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + target: ${{ github.event.inputs.target }} + branch: ${{ github.event.inputs.branch }} + release_url: ${{ github.event.inputs.release_url }} + steps_to_skip: ${{ github.event.inputs.steps_to_skip }} + + - name: Finalize Release + id: finalize-release + env: + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + PYPI_TOKEN_MAP: ${{ secrets.PYPI_TOKEN_MAP }} + TWINE_USERNAME: __token__ + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + uses: jupyter-server/jupyter-releaser/.github/actions/finalize-release@v2 + with: + token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + target: ${{ github.event.inputs.target }} + release_url: ${{ steps.populate-release.outputs.release_url }} + + - name: "** Next Step **" + if: ${{ success() }} + run: | + echo "Verify the final release" + echo ${{ steps.finalize-release.outputs.release_url }} + + - name: "** Failure Message **" + if: ${{ failure() }} + run: | + echo "Failed to Publish the Draft Release Url:" + echo ${{ steps.populate-release.outputs.release_url }} diff --git a/.github/workflows/reject-staging-changes.yml b/.github/workflows/reject-staging-changes.yml new file mode 100644 index 000000000000..1449cc6d73c7 --- /dev/null +++ b/.github/workflows/reject-staging-changes.yml @@ -0,0 +1,30 @@ +# This workflow fails in PRs with changes to the jupyterlab/staging directory +# Won't start unless there is a modification in the staging directory + +name: 'Reject changes to staging' +on: + pull_request: + paths: + - 'jupyterlab/staging/**' + +jobs: + staging-check: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Get modified files in the staging directory + id: modified-files-in-staging + uses: tj-actions/changed-files@v36.0.11 + with: + # only checks for modified files in this directory + files: jupyterlab/staging + # ignores modifications to these files + files_ignore: | + jupyterlab/staging/yarn.js + jupyterlab/staging/.yarnrc + + - name: Fail if files in staging are modified + if: steps.modified-files-in-staging.outputs.any_changed == 'true' + run: exit 1 diff --git a/.github/workflows/windowstests.yml b/.github/workflows/windowstests.yml index a88a4c544d29..26e7cae145eb 100644 --- a/.github/workflows/windowstests.yml +++ b/.github/workflows/windowstests.yml @@ -2,9 +2,9 @@ name: Windows Tests on: push: - branches: [3.6.x] + branches: [4.0.x] pull_request: - branches: [3.6.x] + branches: [4.0.x] release: types: [published] @@ -19,7 +19,7 @@ jobs: timeout-minutes: 40 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 diff --git a/.gitignore b/.gitignore index 8e1f151323c3..d12c3f89ffbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # project files coverage/ +.eslintcache +.stylelintcache dev_mode/listings dev_mode/schemas @@ -9,7 +11,10 @@ dev_mode/workspaces dev_mode/stats.json docs/_build -docs/api +docs/source/user/commands_list.md +docs/source/extension/plugins_list.rst +docs/source/extension/tokens_list.rst +docs/source/api **/docs/source/_build examples/app/build @@ -20,6 +25,7 @@ examples/federated/labextensions junit.xml +jupyterlab/galata/@jupyterlab jupyterlab/geckodriver jupyterlab/static jupyterlab/schemas @@ -33,6 +39,7 @@ ui-tests/test-output # Remove after next release jupyterlab/imports.css +packages/codemirror/test/foo*.js packages/nbconvert-css/style/ packages/services/examples/node/config.json packages/services/examples/browser/tmp @@ -56,7 +63,6 @@ node_modules *.tsbuildinfo lerna-debug.log yarn-error.log -storybook-static # python .cache @@ -68,6 +74,7 @@ __pycache__ pip-wheel-metadata Pipfile Pipfile.lock +venv/ # xeus-python debug logs xpython_debug_logs @@ -107,8 +114,10 @@ lerna-debug.log yarn-error.log # yarn >=2.x local files -.yarn +.yarn/* .pnp.* +jupyterlab/staging/.yarn/* +jupyterlab/staging/.pnp.* # copied changelog file docs/source/getting_started/changelog.md @@ -124,9 +133,14 @@ junit.xml # ms IDE stuff *.code-workspace .history -.vscode -.vs .vscode/* !.vscode/extension.json .jupyter_releaser_checkout + +# generated LSP interfaces +packages/lsp/src/_* + +# generated reports +webpack-bundle-analyzer.html +examples/**/test-results/ diff --git a/.gitpod.yml b/.gitpod.yml index 4970d867b928..1a80e4ac462e 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,33 +1,59 @@ github: prebuilds: - # enable for the master/default branch (defaults to true) master: true - # enable for all branches in this repo (defaults to false) branches: true - # enable for pull requests coming from this repo (defaults to true) pullRequests: true - # enable for pull requests coming from forks (defaults to false) pullRequestsFromForks: true - # add a check to pull requests (defaults to true) addCheck: false - # add a "Review in Gitpod" button as a comment to pull requests (defaults to false) addComment: false - # add a "Review in Gitpod" button to the pull request's description (defaults to false) addBadge: false - # add a label once the prebuild is ready to pull requests (defaults to false) addLabel: false tasks: - - init: pip3 install -e . && yarn install && yarn run build - # for some reason,have to re-install on start, or else it doesn't find the python package - # Set no token and allow any origin, so that you can open it in a new tab - # Disable iframe security so can load in the editor as well - command: > - pip3 install -e . && - jupyter lab - --dev-mode - --watch - --LabApp.token='' - --LabApp.allow_origin=* - --LabApp.tornado_settings='{"headers": {"Content-Security-Policy": "frame-ancestors *"}}' + - name: setup + init: | + pushd /workspace + wget -qO- https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba + popd + # bootstrap activation commands for other tasks to reuse + cat < /workspace/bin/activate-env.sh + export MAMBA_ROOT_PREFIX=/workspace/.micromamba + export MAMBA_EXE=/workspace/bin/micromamba + $(/workspace/bin/micromamba shell hook --shell=bash) + export JUPYTER_PREFER_ENV_PATH=1 + micromamba activate + EOT + source /workspace/bin/activate-env.sh + micromamba config append channels conda-forge + micromamba install -n base -y python=3.10 nodejs=18 yarn + source /workspace/bin/activate-env.sh + python -m pip install -e ".[dev,docs,test]" && jlpm install && jlpm run build + gp sync-done setup + command: | + gp sync-done setup + source /workspace/bin/activate-env.sh + # Set no token and allow any origin, so that you can open it in a new tab + # Disable iframe security so can load in the editor as well + jupyter lab --dev-mode --watch --extensions-in-dev-mode --ServerApp.IdentityProvider.token='' --ServerApp.allow_origin=* --ServerApp.tornado_settings='{"headers": {"Content-Security-Policy": "frame-ancestors *"}}' + + - name: auto-activate + command: | + gp sync-await setup + echo "source /workspace/bin/activate-env.sh" >> ~/.bashrc + source /workspace/bin/activate-env.sh + + - name: documentation + command: | + gp sync-await setup + source /workspace/bin/activate-env.sh + cd docs + make html + cd build/html + python -m http.server 8000 + ports: - port: 8888 + - port: 8000 + +vscode: + extensions: + - esbenp.prettier-vscode diff --git a/.licenserc.yaml b/.licenserc.yaml index fce386c82496..1d4c9c8a1712 100644 --- a/.licenserc.yaml +++ b/.licenserc.yaml @@ -32,6 +32,7 @@ header: - 'dev_mode/style.js' - 'examples/federated/example.cert' - 'galata/test/jupyterlab/notebooks/' + - 'jupyterlab.desktop' - 'jupyterlab/staging' - 'packages/codemirror/test/foo.grammar' - 'packages/extensionmanager-extension/examples/listings/settings/@jupyterlab/extensionmanager-extension/plugin.jupyterlab-settings' diff --git a/.meeseeksdev.yml b/.meeseeksdev.yml index 165a153db576..96e0541a5a90 100644 --- a/.meeseeksdev.yml +++ b/.meeseeksdev.yml @@ -1,6 +1,6 @@ special: everyone: - can: + can: - say - tag - - untag \ No newline at end of file + - untag diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1a58e4716c59..7edcc55f2f49 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,31 +1,46 @@ ci: + # Same schedule interval as dependabot see .github/dependabot.yml + autoupdate_schedule: monthly # skip any check that needs internet access - skip: [check-jsonschema, prettier, eslint, integrity] + skip: [prettier, eslint, stylelint] + +default_language_version: + node: system repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.4.0 hooks: - id: forbid-new-submodules + - id: end-of-file-fixer + exclude: galata/.*-snapshots - id: check-case-conflict + - id: check-executables-have-shebangs - id: requirements-txt-fixer - id: check-added-large-files - id: check-case-conflict + - id: check-toml + - id: check-yaml - id: debug-statements + - id: check-builtin-literals + - id: trailing-whitespace + exclude: (.bumpversion.cfg|yarn.js) + + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.27.0 + hooks: + - id: check-github-workflows - - repo: https://github.com/executablebooks/mdformat - rev: 0.7.16 + - repo: https://github.com/psf/black + rev: 23.9.1 hooks: - - id: mdformat + - id: black - - repo: https://github.com/sirosen/check-jsonschema - rev: 0.14.2 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.292 hooks: - - id: check-jsonschema - name: 'Check GitHub Workflows' - files: ^\.github/workflows/ - types: [yaml] - args: ['--schemafile', 'https://json.schemastore.org/github-workflow'] + - id: ruff + args: ["--fix"] - repo: local hooks: @@ -39,6 +54,11 @@ repos: entry: 'npm run eslint:files' language: node types_or: [ts, tsx, javascript, jsx] + - id: stylelint + name: stylelint + entry: 'npm run stylelint:files' + language: node + types: [css] - id: integrity name: integrity entry: 'npm run integrity --force' diff --git a/.prettierignore b/.prettierignore index 2b6ab9f9f839..5da1f9596629 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,10 +1,12 @@ **/build **/node_modules **/lib +**/dist **/package.json **/static **/.ipynb_checkpoints -tests/**/coverage +**/coverage +CHANGELOG.md .eggs dev_mode/index.js @@ -13,23 +15,27 @@ dev_mode/static dev_mode/themes dev_mode/workspaces docs/_build +docs/build docs/api examples/app/build examples/app/themes examples/app/schemas examples/federated/core_package/index.template.js +examples/federated/core_package/index.js +examples/federated/labextensions +galata/playwright-report +jupyterlab/galata jupyterlab/schemas jupyterlab/themes jupyterlab/geckodriver jupyterlab/staging/yarn.js +jupyterlab/staging/yarn.lock jupyterlab/staging/index.js +jupyterlab/staging/webpack.config.js packages/ui-components/src/icon/iconimports.ts -packages/extensionmanager/examples/listings tsconfigdoc.json -galata/playwright-report -examples/federated/core_package/index.js -examples/federated/labextensions -CHANGELOG.md +typedoc-theme +yarn.lock # jetbrains IDE stuff .idea/ @@ -40,3 +46,15 @@ CHANGELOG.md # autogenerated from a lot of css in jlab packages/nbconvert-css/style/index.css + +# autogenerated files for documentation +docs/source/user/commands_list.md +docs/source/extensions/plugins_list.rst +docs/source/extensions/tokens_list.rst +galata/test/documentation/*/*.json + +# generated LSP interfaces +packages/lsp/src/_ + +# generated by reports +stats.json diff --git a/.prettierrc b/.prettierrc index 1950328e59aa..b0a179d48cb8 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,4 +2,4 @@ "singleQuote": true, "trailingComma": "none", "arrowParens": "avoid" -} \ No newline at end of file +} diff --git a/.readthedocs.yml b/.readthedocs.yml index dd28db48a1c7..f21eb589a28f 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,11 +1,17 @@ version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.10" + nodejs: "18" + sphinx: configuration: docs/source/conf.py -conda: - environment: docs/environment.yml + python: - version: 3.7 install: - # install jupyterlab itself - method: pip path: . + extra_requirements: + - docs diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 000000000000..7f5ba552b538 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,5 @@ +packages/nbconvert-css/style/index.css + +docs/_build +docs/build +docs/api diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml new file mode 100644 index 000000000000..5d14b3f44e41 --- /dev/null +++ b/.stylelintrc.yaml @@ -0,0 +1,47 @@ +$schema: https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/stylelintrc.json + +extends: + - stylelint-config-recommended + - stylelint-config-standard + - stylelint-prettier/recommended + +plugins: + - stylelint-csstree-validator + +rules: + import-notation: null + # TODO: fix all of these rules violated in stylelint-config-recommended + no-descending-specificity: null + # this fixer is incompatible with the copyright headers + comment-whitespace-inside: null + # these fixers assume use of `autoprefixer`: we _don't_ use any CSS preprocessors + property-no-vendor-prefix: null + selector-no-vendor-prefix: null + value-no-vendor-prefix: null + # these fixers doesn't work well with variables + alpha-value-notation: null + color-function-notation: null + # TODO: evaluate these unfixable rules violated in stylelint-config-standard + custom-property-pattern: null + declaration-block-no-redundant-longhand-properties: null + function-linear-gradient-no-nonstandard-direction: null + function-url-quotes: null + keyframes-name-pattern: null + number-max-precision: null + selector-class-pattern: null + selector-id-pattern: null + selector-pseudo-class-no-unknown: null + selector-pseudo-element-no-unknown: null + selector-not-notation: null + # disallow use of more than one bare HTML tag like `div span` to avoid performance regression, + # while allowing compounded HTML tags like `button.jp-Button` + selector-max-type: + - 1 + - ignore: "compounded" + # matching complex selectors is expensive + selector-max-class: 4 + # TODO: decrease max-compound to 3 + selector-max-compound-selectors: 4 + # TODO: decrease to 0 + selector-max-universal: 1 + csstree/validator: true diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000000..ba866a081812 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "esbenp.prettier-vscode", + ], +} diff --git a/.yarnrc b/.yarnrc deleted file mode 100644 index 9751ca9a39b6..000000000000 --- a/.yarnrc +++ /dev/null @@ -1,2 +0,0 @@ -yarn-path "./jupyterlab/staging/yarn.js" -ignore-optional true diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 000000000000..d1027ee74005 --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1,25 @@ +enableImmutableInstalls: false + +enableInlineBuilds: false + +enableTelemetry: false + +httpTimeout: 60000 + +logFilters: + - code: YN0006 + level: discard + - code: YN0007 + level: discard + - code: YN0008 + level: discard + - code: YN0013 + level: discard + - code: YN0019 + level: discard + +nodeLinker: node-modules + +npmRegistryServer: "https://registry.yarnpkg.com" + +yarnPath: ./jupyterlab/staging/yarn.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 27ef937109e3..369384dc5fe8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,120 +4,1334 @@ # JupyterLab Changelog -## v3.6 +## v4.0 + +### 4.0.0 - Highlights + +Below are the major highlights in JupyterLab 4.0.0. + +#### New text editor + +CodeMirror, the text editor used for cells and file editors, has been updated to [CodeMirror 6](https://codemirror.net/). This brings important +accessibility and performance improvements as well as better customization capabilities. +We have also improved the editor settings. Previously, users had to customize settings separately for each type of cell, the file editor, and the console editor. Now, you can change your settings in one place. It is now easier to use the default settings for all editors and to change some settings for specific cases. For example, you can now hide line numbers only for markdown cells. + +Developers can now provide editor extensions, like themes and programming language parsers, through new application registries. + +#### New extension manager + +Starting with JupyterLab 3, extensions can be installed via Python packages +(or other providers of [prebuilt extensions](https://jupyterlab.readthedocs.io/en/stable/extension/extension_dev.html#prebuilt-extensions)). + +In JupyterLab 4, building on this feature, the Extension Manager now includes extensions from [pypi.org](https://pypi.org/search/?c=Framework+%3A%3A+Jupyter+%3A%3A+JupyterLab). +This removes the build step from installation of extension when using Extension Manager. + +Developers can provide an alternative package repository to display their own set of extensions. + +#### Improved document search + +The Search and Replace functionality has been improved with new features when searching in a notebook: + +- Highlight matches in rendered markdown cells +- Search in selection +- Multi-line search +- Replace using regex capture-group references +- Replace while preserving case + +#### UI improvements + +Some new elements have been added or changed in the UI: + +- Rework the running kernels section +- "Add a new cell" button at the bottom of a notebook +- Dialog to display keyboard shortcuts as in the Classic Notebook (use Ctrl + Shift + H) +- Display the first line of cell input and outputs when they are collapsed + +#### Accessibility improvements + +JupyterLab is not yet fully accessible. Currently, we are focused on making Notebook 7 accessible. +A big part of the code is shared, though, and the following accessibility improvements are in JupyterLab 4: + +- Improved focus and keyboard navigation in the file browser +- More ARIA roles and labels were added to UI elements +- Main menu collapses to a hamburger menu if there is not enough space to display all items. + +#### Performance enhancements + +JupyterLab is now faster, thanks to the following improvements: + +- CSS rules optimization: CSS selectors have been optimized to improve web browser performance when many elements are present on a page. +- Upgrade to CodeMirror 6: Especially for notebooks with many cells, the new CodeMirror version is far more efficient than the previous version. Large notebooks should load more quickly. +- Upgrade to MathJax 3: The mathematical equations renderer library has been been upgraded from v2 to v3 allowing faster rendering. +- Notebook windowing: By rendering only the parts of a notebook that fit in the web browser viewport, JupyterLab is much more efficient. See an important note below. + +Notebook windowing _might_ add side effects for example if some cell outputs are displaying [iframes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe). Therefore it is not yet the default value. But we recommend user to switch to it and report bugs to help us polish it. To test it, you +need to set the user setting _Notebook_ > _Windowing mode_ to `full`. If you have issues with notebook rendering, try changing back to `defer` or `none`. (`none` should be used as a last resort, because it disables all optimizations.) + +#### Real Time Collaboration + +JupyterLab 3.6 already made significant improvements to the Real Time Collaboration (RTC) feature. +The feature is now in a separate repository: [jupyter_collaboration](https://github.com/jupyterlab/jupyter_collaboration). +The rationale is to limit the dependencies for users who don't need RTC. Separating RTC also helps organizations using JupyterLab that do not meet the specific requirements regarding file content management. + +To enable RTC, install the `jupyter-collaboration` package with either `pip` or `conda`. + +- with pip: `pip install "jupyter-collaboration>=1.0.0a0"` +- with conda: _not yet available_ + +RTC highlights in the standalone `jupyter-collboration` package, version 1.0.0, include: + +- Support for displaying multiple cursors and selections +- Support for registration of new shared model types + +#### For developers + +Here are the main tool updates that will benefit extension authors and developers: + +- TypeScript v5 +- Yarn v3 +- React v18 +- Lumino v2 + +We recommend using Node.js v18 or newer, because older versions will reach end of life in 2023 or earlier (see [Node release schedule](https://github.com/nodejs/release#release-schedule)). + +To ease code migration to JupyterLab 4, developers should review the [migration guide](https://jupyterlab.readthedocs.io/en/stable/extension/extension_migration.html). A few existing extensions have already been migrated and can be used as examples: +- the [JupyterLab Extensions by Examples](https://github.com/jupyterlab/extension-examples/pull/232) +- the [Jupyter MIME type renderers](https://github.com/jupyterlab/jupyter-renderers/pull/296) -## 3.6.6 +## 4.0.8 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.7...86078b863e794fe26154576118dae972f071ea2f)) + +### Enhancements made + +- Expand search box horizontally when text grows long [#15266](https://github.com/jupyterlab/jupyterlab/pull/15266) ([@sinistersnare](https://github.com/sinistersnare)) + +### Bugs fixed + +- Add min width to constrain resizing in side-by-side view [#14529](https://github.com/jupyterlab/jupyterlab/pull/14529) ([@dharmaquark](https://github.com/dharmaquark)) +- Fix collapsed cells styling [#15322](https://github.com/jupyterlab/jupyterlab/pull/15322) ([@fcollonval](https://github.com/fcollonval)) +- Fix autobrackets and other default CM extension [#15297](https://github.com/jupyterlab/jupyterlab/pull/15297) ([@fcollonval](https://github.com/fcollonval)) +- Fix rulers position with gutter width [#15296](https://github.com/jupyterlab/jupyterlab/pull/15296) ([@fcollonval](https://github.com/fcollonval)) +- Declare Webpack loaders with `require.resolve()` [#15299](https://github.com/jupyterlab/jupyterlab/pull/15299) ([@tibdex](https://github.com/tibdex)) + +### Maintenance and upkeep improvements + +- Backport ruff/black/pre-commit updates to align versions [#15345](https://github.com/jupyterlab/jupyterlab/pull/15345) ([@krassowski](https://github.com/krassowski)) +- Turn off navigation with keys [#15310](https://github.com/jupyterlab/jupyterlab/pull/15310) ([@fcollonval](https://github.com/fcollonval)) +- Update benchmark reporter snapshots [#15279](https://github.com/jupyterlab/jupyterlab/pull/15279) ([@krassowski](https://github.com/krassowski)) +- Update canvas to a version with prebuilds for nodeJS 20 [#15270](https://github.com/jupyterlab/jupyterlab/pull/15270) ([@fcollonval](https://github.com/fcollonval)) +- Commit JS and Python packages in one commit on release [#15042](https://github.com/jupyterlab/jupyterlab/pull/15042) ([@jtpio](https://github.com/jtpio)) + +### Documentation improvements + +- Expand search box horizontally when text grows long [#15266](https://github.com/jupyterlab/jupyterlab/pull/15266) ([@sinistersnare](https://github.com/sinistersnare)) +- Turn off navigation with keys [#15310](https://github.com/jupyterlab/jupyterlab/pull/15310) ([@fcollonval](https://github.com/fcollonval)) +- Fixed home page link to sibling project. [#15256](https://github.com/jupyterlab/jupyterlab/pull/15256) ([@ericsnekbytes](https://github.com/ericsnekbytes)) +- Commit JS and Python packages in one commit on release [#15042](https://github.com/jupyterlab/jupyterlab/pull/15042) ([@jtpio](https://github.com/jtpio)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2023-10-11&to=2023-11-02&type=c)) + +[@andrii-i](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrii-i+updated%3A2023-10-11..2023-11-02&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2023-10-11..2023-11-02&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2023-10-11..2023-11-02&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2023-10-11..2023-11-02&type=Issues) | [@j264415](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aj264415+updated%3A2023-10-11..2023-11-02&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2023-10-11..2023-11-02&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2023-10-11..2023-11-02&type=Issues) | [@lumberbot-app](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Alumberbot-app+updated%3A2023-10-11..2023-11-02&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2023-10-11..2023-11-02&type=Issues) | [@tonyfast](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atonyfast+updated%3A2023-10-11..2023-11-02&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2023-10-11..2023-11-02&type=Issues) + + -([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.6.5...b86cc202967e8231560f5d67f3daa747a7d3ad79)) +## 4.0.7 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.6...277bd0b0dbf28688149ed2bc62830b7d67e6ad21)) + +### Enhancements made + +- Add the standard SQL mimetype [#15180](https://github.com/jupyterlab/jupyterlab/pull/15180) ([@brichet](https://github.com/brichet)) + +### Bugs fixed + +- Restore horizontal scrolling of outputs for Firefox [#15171](https://github.com/jupyterlab/jupyterlab/pull/15171) ([@fcollonval](https://github.com/fcollonval)) +- Fix text wrapping in the search box [#15080](https://github.com/jupyterlab/jupyterlab/pull/15080) ([@eliaslma](https://github.com/eliaslma)) +- Fix completer documentation panel hiding and animation [#15238](https://github.com/jupyterlab/jupyterlab/pull/15238) ([@krassowski](https://github.com/krassowski)) +- Fix clicking in the TOC does not scroll [#15184](https://github.com/jupyterlab/jupyterlab/pull/15184) ([@parmentelat](https://github.com/parmentelat)) +- Hide completer when changing notebook tabs [#14534](https://github.com/jupyterlab/jupyterlab/pull/14534) ([@nishikantparmariam](https://github.com/nishikantparmariam)) +- Backport of MathJax double init/font URL fix and binder/log updates [#15231](https://github.com/jupyterlab/jupyterlab/pull/15231) ([@bollwyvl](https://github.com/bollwyvl)) +- Restore syntax highlighting for mimetypes with more than one identifier [#15175](https://github.com/jupyterlab/jupyterlab/pull/15175) ([@jans-code](https://github.com/jans-code)) +- Fix completer width inflation and jitter [#15132](https://github.com/jupyterlab/jupyterlab/pull/15132) ([@krassowski](https://github.com/krassowski)) +- Fix Show Keyboard Shortcuts command [#15170](https://github.com/jupyterlab/jupyterlab/pull/15170) ([@jtpio](https://github.com/jtpio)) +- Blur footer for any key that triggers a 'select above', not just ArrowUp [#14796](https://github.com/jupyterlab/jupyterlab/pull/14796) ([@smacke](https://github.com/smacke)) +- Fix background-color in `` instead of using universal CSS selector [#14408](https://github.com/jupyterlab/jupyterlab/pull/14408) ([@fcollonval](https://github.com/fcollonval)) +- Improve scrolling for insert cell and run and advance [#14407](https://github.com/jupyterlab/jupyterlab/pull/14407) ([@fcollonval](https://github.com/fcollonval)) +- Remove Brainf... parser [#14406](https://github.com/jupyterlab/jupyterlab/pull/14406) ([@fcollonval](https://github.com/fcollonval)) +- Restore rectangular selection (CodeMirror 6 migration follow-up) [#14384](https://github.com/jupyterlab/jupyterlab/pull/14384) ([@krassowski](https://github.com/krassowski)) +- Make cell toolbar background transparent [#14382](https://github.com/jupyterlab/jupyterlab/pull/14382) ([@krassowski](https://github.com/krassowski)) +- Add signal when an item factory is added to the toolbar [#14376](https://github.com/jupyterlab/jupyterlab/pull/14376) ([@brichet](https://github.com/brichet)) +- Fix cursor when hovering a kernel in the Running tab [#14369](https://github.com/jupyterlab/jupyterlab/pull/14369) ([@yumyumqing](https://github.com/yumyumqing)) +- Fix search highlight in selection anchor of cell selection [#14356](https://github.com/jupyterlab/jupyterlab/pull/14356) ([@krassowski](https://github.com/krassowski)) +- Ensure that initial text is updated on subsequent searches [#14353](https://github.com/jupyterlab/jupyterlab/pull/14353) ([@krassowski](https://github.com/krassowski)) +- Fix "additional properties" settings editor validation error [#14346](https://github.com/jupyterlab/jupyterlab/pull/14346) ([@marthacryan](https://github.com/marthacryan)) +- Align notebook trust behaviour with trust in classic Notebook [#14345](https://github.com/jupyterlab/jupyterlab/pull/14345) ([@krassowski](https://github.com/krassowski)) +- Adds buffer, uses zoom cursors for cell output collapser (supersedes #14266) [#14344](https://github.com/jupyterlab/jupyterlab/pull/14344) ([@andrii-i](https://github.com/andrii-i)) +- Resolve jest binary path in test:debug [#14336](https://github.com/jupyterlab/jupyterlab/pull/14336) ([@fcollonval](https://github.com/fcollonval)) +- Fix failure when setting debugger variables filter [#14321](https://github.com/jupyterlab/jupyterlab/pull/14321) ([@afshin](https://github.com/afshin)) +- Upgrades @lumino/commands to 2.0.1, fixing emoji "enter" on macOS [#14305](https://github.com/jupyterlab/jupyterlab/pull/14305) ([@JasonWeill](https://github.com/JasonWeill)) +- Fix examples further to CodeMirror API change [#14293](https://github.com/jupyterlab/jupyterlab/pull/14293) ([@echarles](https://github.com/echarles)) +- Fix color contrast of gutter line numbers in code mirror [#14269](https://github.com/jupyterlab/jupyterlab/pull/14269) ([@andrii-i](https://github.com/andrii-i)) +- Exclude .yarn cache from the dist [#14242](https://github.com/jupyterlab/jupyterlab/pull/14242) ([@martinRenou](https://github.com/martinRenou)) - Fix cursor placement in stdin history search and navigation [#14225](https://github.com/jupyterlab/jupyterlab/pull/14225) ([@krassowski](https://github.com/krassowski)) +- Fix save as without changing the file name [#14212](https://github.com/jupyterlab/jupyterlab/pull/14212) ([@hbcarlos](https://github.com/hbcarlos)) +- Update jupyter-lsp and associated schema [#14208](https://github.com/jupyterlab/jupyterlab/pull/14208) ([@fcollonval](https://github.com/fcollonval)) +- Suppresses header check inside frontmatter [#14203](https://github.com/jupyterlab/jupyterlab/pull/14203) ([@JasonWeill](https://github.com/JasonWeill)) +- CodeMirror packages has singletons [#14199](https://github.com/jupyterlab/jupyterlab/pull/14199) ([@fcollonval](https://github.com/fcollonval)) +- Make codemirror state and view packages singleton [#14183](https://github.com/jupyterlab/jupyterlab/pull/14183) ([@fcollonval](https://github.com/fcollonval)) +- Fix save as in collaborative mode [#14182](https://github.com/jupyterlab/jupyterlab/pull/14182) ([@hbcarlos](https://github.com/hbcarlos)) +- Decodes URI before adding it to the tab title [#14178](https://github.com/jupyterlab/jupyterlab/pull/14178) ([@hbcarlos](https://github.com/hbcarlos)) +- Do not update running list when hidden [#14172](https://github.com/jupyterlab/jupyterlab/pull/14172) ([@krassowski](https://github.com/krassowski)) +- Keep extension manager panel sizes when pagination changes [#14171](https://github.com/jupyterlab/jupyterlab/pull/14171) ([@FoSuCloud](https://github.com/FoSuCloud)) +- Fix link colors #14084 (Previous PR #14129) [#14159](https://github.com/jupyterlab/jupyterlab/pull/14159) ([@damiend97](https://github.com/damiend97)) +- Fix create-package [#14156](https://github.com/jupyterlab/jupyterlab/pull/14156) ([@fcollonval](https://github.com/fcollonval)) +- Fix getting current without activation for labels and captions [#14152](https://github.com/jupyterlab/jupyterlab/pull/14152) ([@fcollonval](https://github.com/fcollonval)) +- bug: Add fallback value for undefined className prop in GroupItem component [#14140](https://github.com/jupyterlab/jupyterlab/pull/14140) ([@zrottman](https://github.com/zrottman)) +- Fixes contextual help attachment logic [#14120](https://github.com/jupyterlab/jupyterlab/pull/14120) ([@JasonWeill](https://github.com/JasonWeill)) +- Hide `` block in the UI when there is an error installing any extension. [#14095](https://github.com/jupyterlab/jupyterlab/pull/14095) ([@kamalika0363](https://github.com/kamalika0363)) +- Search boxes: switch to `defaultValue`, add a test for typing [#14085](https://github.com/jupyterlab/jupyterlab/pull/14085) ([@krassowski](https://github.com/krassowski)) +- Fix extension manager button background color [#14079](https://github.com/jupyterlab/jupyterlab/pull/14079) ([@jtpio](https://github.com/jtpio)) +- Fix code/content/ui font-size change [#14077](https://github.com/jupyterlab/jupyterlab/pull/14077) ([@FoSuCloud](https://github.com/FoSuCloud)) +- Styling fixes for rjsm Settings Editor: remove accordions, rework "Restore to defaults" button, add placeholder [#14074](https://github.com/jupyterlab/jupyterlab/pull/14074) ([@andrii-i](https://github.com/andrii-i)) +- Property inspector styling fixes [#14069](https://github.com/jupyterlab/jupyterlab/pull/14069) ([@JasonWeill](https://github.com/JasonWeill)) +- Debugger: check `hasCommand` before calling `notifyCommandChanged` [#14066](https://github.com/jupyterlab/jupyterlab/pull/14066) ([@jtpio](https://github.com/jtpio)) +- Fix non-document wide undo stack [#14063](https://github.com/jupyterlab/jupyterlab/pull/14063) ([@fcollonval](https://github.com/fcollonval)) +- use singleton boolean type for codemirror `lineWiseCopyCut` setting [#14055](https://github.com/jupyterlab/jupyterlab/pull/14055) ([@bollwyvl](https://github.com/bollwyvl)) +- Fix attachments [#14052](https://github.com/jupyterlab/jupyterlab/pull/14052) ([@hbcarlos](https://github.com/hbcarlos)) +- Minor trust improvements [#14039](https://github.com/jupyterlab/jupyterlab/pull/14039) ([@krassowski](https://github.com/krassowski)) +- Adds placeholder when TOC is empty [#14024](https://github.com/jupyterlab/jupyterlab/pull/14024) ([@JasonWeill](https://github.com/JasonWeill)) +- Galata config helper should not set dev_mode [#14012](https://github.com/jupyterlab/jupyterlab/pull/14012) ([@fcollonval](https://github.com/fcollonval)) +- Restore using `runmenu:restart-an-run-all` [#14000](https://github.com/jupyterlab/jupyterlab/pull/14000) ([@fcollonval](https://github.com/fcollonval)) +- Fix galata update job [#13999](https://github.com/jupyterlab/jupyterlab/pull/13999) ([@fcollonval](https://github.com/fcollonval)) +- Use node 18 for benchmark [#13982](https://github.com/jupyterlab/jupyterlab/pull/13982) ([@fcollonval](https://github.com/fcollonval)) +- Hides cell toolbar when cell is collapsed [#13964](https://github.com/jupyterlab/jupyterlab/pull/13964) ([@JasonWeill](https://github.com/JasonWeill)) +- Dispose properly objects [#13960](https://github.com/jupyterlab/jupyterlab/pull/13960) ([@fcollonval](https://github.com/fcollonval)) +- Fixes toolbar button for Restart Kernel and Run All [#13939](https://github.com/jupyterlab/jupyterlab/pull/13939) ([@JasonWeill](https://github.com/JasonWeill)) +- Fix LSP adapter errors on tab close [#13918](https://github.com/jupyterlab/jupyterlab/pull/13918) ([@afshin](https://github.com/afshin)) +- Hide the cell toolbar on mobile / screens less than 760px wide to prevent cell obstruction [#13896](https://github.com/jupyterlab/jupyterlab/pull/13896) ([@andrii-i](https://github.com/andrii-i)) +- Define colour and background for filebrowser edit field [#13895](https://github.com/jupyterlab/jupyterlab/pull/13895) ([@krassowski](https://github.com/krassowski)) +- Create a unified editor search provider [#13884](https://github.com/jupyterlab/jupyterlab/pull/13884) ([@krassowski](https://github.com/krassowski)) +- Fix searching backwards in notebook [#13883](https://github.com/jupyterlab/jupyterlab/pull/13883) ([@krassowski](https://github.com/krassowski)) +- Waits for panel reveal before measuring first cell for cell toolbar [#13876](https://github.com/jupyterlab/jupyterlab/pull/13876) ([@JasonWeill](https://github.com/JasonWeill)) +- Fixes notebook's metadata in collaborative mode [#13868](https://github.com/jupyterlab/jupyterlab/pull/13868) ([@hbcarlos](https://github.com/hbcarlos)) +- Use local paths instead of driveName:path in the shared model [#13866](https://github.com/jupyterlab/jupyterlab/pull/13866) ([@hbcarlos](https://github.com/hbcarlos)) +- Updates jupyter_server_ydoc [#13854](https://github.com/jupyterlab/jupyterlab/pull/13854) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix undefined css variables [#13852](https://github.com/jupyterlab/jupyterlab/pull/13852) ([@HaudinFlorence](https://github.com/HaudinFlorence)) +- Suppresses cell toolbar on collapsed input cells [#13847](https://github.com/jupyterlab/jupyterlab/pull/13847) ([@JasonWeill](https://github.com/JasonWeill)) +- Removes nested A tag from extensionmanager code [#13845](https://github.com/jupyterlab/jupyterlab/pull/13845) ([@JasonWeill](https://github.com/JasonWeill)) +- Reset execution indicator state when kernel restarts [#13832](https://github.com/jupyterlab/jupyterlab/pull/13832) ([@krassowski](https://github.com/krassowski)) +- Fix starting search with selected text (if any) [#13802](https://github.com/jupyterlab/jupyterlab/pull/13802) ([@krassowski](https://github.com/krassowski)) +- Updates to the kernel panel of the "running" sidebar [#13792](https://github.com/jupyterlab/jupyterlab/pull/13792) ([@afshin](https://github.com/afshin)) +- Fix `preferred_dir` for examples [#13788](https://github.com/jupyterlab/jupyterlab/pull/13788) ([@fcollonval](https://github.com/fcollonval)) +- Bump canvas to version with nodejs 18 binaries [#13783](https://github.com/jupyterlab/jupyterlab/pull/13783) ([@fcollonval](https://github.com/fcollonval)) +- Explain why cell model may be missing in cell toolbar [#13763](https://github.com/jupyterlab/jupyterlab/pull/13763) ([@krassowski](https://github.com/krassowski)) +- Fix handling of `settingEditorType` [#13761](https://github.com/jupyterlab/jupyterlab/pull/13761) ([@jtpio](https://github.com/jtpio)) +- Updates jupyter_ydoc [#13735](https://github.com/jupyterlab/jupyterlab/pull/13735) ([@hbcarlos](https://github.com/hbcarlos)) +- Wrap kernel message binary buffers in DataView [#13730](https://github.com/jupyterlab/jupyterlab/pull/13730) ([@davidbrochart](https://github.com/davidbrochart)) +- Upgrades Python to 3.10, Node to 18 [#13722](https://github.com/jupyterlab/jupyterlab/pull/13722) ([@JasonWeill](https://github.com/JasonWeill)) +- Fix CodeQL warning [#13712](https://github.com/jupyterlab/jupyterlab/pull/13712) ([@fcollonval](https://github.com/fcollonval)) +- Faster rendering of the debugger tree [#13707](https://github.com/jupyterlab/jupyterlab/pull/13707) ([@krassowski](https://github.com/krassowski)) +- Fix execution indicator in RTC mode [#13693](https://github.com/jupyterlab/jupyterlab/pull/13693) ([@trungleduc](https://github.com/trungleduc)) +- Update plugin ID of hub extension [#13688](https://github.com/jupyterlab/jupyterlab/pull/13688) ([@mctoohey](https://github.com/mctoohey)) +- Fix contrast on the plugin list, add screenshots to catch regressions [#13661](https://github.com/jupyterlab/jupyterlab/pull/13661) ([@krassowski](https://github.com/krassowski)) +- Fix `replaceSelection`, add unit test [#13657](https://github.com/jupyterlab/jupyterlab/pull/13657) ([@krassowski](https://github.com/krassowski)) +- Fix `RunningTerminal` access before initialization [#13655](https://github.com/jupyterlab/jupyterlab/pull/13655) ([@krassowski](https://github.com/krassowski)) +- Write the browser open files for test [#13634](https://github.com/jupyterlab/jupyterlab/pull/13634) ([@fcollonval](https://github.com/fcollonval)) +- Fix select wrapping in inputDialog [#13622](https://github.com/jupyterlab/jupyterlab/pull/13622) ([@brichet](https://github.com/brichet)) +- Does not prevent default behavior when shift-clicking [#13616](https://github.com/jupyterlab/jupyterlab/pull/13616) ([@jmk89](https://github.com/jmk89)) +- Fix issue #13569: `source_hidden` not effective. [#13611](https://github.com/jupyterlab/jupyterlab/pull/13611) ([@yczhangsjtu](https://github.com/yczhangsjtu)) +- Add the `scaleFactor` value from the embed options when creating the PNG representation for a Vega-based chart [#13610](https://github.com/jupyterlab/jupyterlab/pull/13610) ([@joaopalmeiro](https://github.com/joaopalmeiro)) +- use jupyter_config_dir instead of config_path\[0\] for workspaces, settings [#13589](https://github.com/jupyterlab/jupyterlab/pull/13589) ([@minrk](https://github.com/minrk)) +- Revert change to active menu bar item [#13576](https://github.com/jupyterlab/jupyterlab/pull/13576) ([@fcollonval](https://github.com/fcollonval)) +- Restores the appearance of the settingeditor's input focus [#13554](https://github.com/jupyterlab/jupyterlab/pull/13554) ([@brichet](https://github.com/brichet)) +- Fix a wrong argument when calling 'renderMimeVariable' [#13531](https://github.com/jupyterlab/jupyterlab/pull/13531) ([@brichet](https://github.com/brichet)) +- Set corrections to icons and switch colors [#13500](https://github.com/jupyterlab/jupyterlab/pull/13500) ([@HaudinFlorence](https://github.com/HaudinFlorence)) +- Default `IDocumentProviderFactory.IOptions` generic to ISharedDocument [#13490](https://github.com/jupyterlab/jupyterlab/pull/13490) ([@jtpio](https://github.com/jtpio)) +- Use same key for saving user info in local store [#13482](https://github.com/jupyterlab/jupyterlab/pull/13482) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix syntax highlighting for JSON viewer in Jupyter Notebook [#13470](https://github.com/jupyterlab/jupyterlab/pull/13470) ([@kostyafarber](https://github.com/kostyafarber)) +- Set fallback values for icons colors. [#13468](https://github.com/jupyterlab/jupyterlab/pull/13468) ([@HaudinFlorence](https://github.com/HaudinFlorence)) +- enable document model specific collaboration [#13458](https://github.com/jupyterlab/jupyterlab/pull/13458) ([@dlqqq](https://github.com/dlqqq)) +- Fix token based completions, restore deduplication, follow up on completer refactor [#13454](https://github.com/jupyterlab/jupyterlab/pull/13454) ([@krassowski](https://github.com/krassowski)) +- Fix `FileEditor.ready` [#13426](https://github.com/jupyterlab/jupyterlab/pull/13426) ([@krassowski](https://github.com/krassowski)) +- Make focus visible (mostly CSS) [#13415](https://github.com/jupyterlab/jupyterlab/pull/13415) ([@gabalafou](https://github.com/gabalafou)) +- Remove metadata entries [#13371](https://github.com/jupyterlab/jupyterlab/pull/13371) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix dirty propagation from shared model [#13368](https://github.com/jupyterlab/jupyterlab/pull/13368) ([@fcollonval](https://github.com/fcollonval)) +- Correct `dirty` handling in notebook model [#13358](https://github.com/jupyterlab/jupyterlab/pull/13358) ([@fcollonval](https://github.com/fcollonval)) +- Handle missing user service [#13353](https://github.com/jupyterlab/jupyterlab/pull/13353) ([@fcollonval](https://github.com/fcollonval)) +- Avoids use of @deprecated to refer to a parameter [#13309](https://github.com/jupyterlab/jupyterlab/pull/13309) ([@JasonWeill](https://github.com/JasonWeill)) +- Updates JSONEditor's source only when there is an active cell or an active notebook panel [#13308](https://github.com/jupyterlab/jupyterlab/pull/13308) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix border-radius does not follow css variable [#13289](https://github.com/jupyterlab/jupyterlab/pull/13289) ([@vthinkxie](https://github.com/vthinkxie)) +- Fix notebook trust in RTC [#13273](https://github.com/jupyterlab/jupyterlab/pull/13273) ([@davidbrochart](https://github.com/davidbrochart)) +- Set `isUntitled` to false on document path changes [#13268](https://github.com/jupyterlab/jupyterlab/pull/13268) ([@fcollonval](https://github.com/fcollonval)) +- Don't dispose the notebook metadata editor on active cell change [#13259](https://github.com/jupyterlab/jupyterlab/pull/13259) ([@fcollonval](https://github.com/fcollonval)) +- Remove some unused CSS styles and fix icon alignment in plugin list [#13255](https://github.com/jupyterlab/jupyterlab/pull/13255) ([@krassowski](https://github.com/krassowski)) +- Do not show side panel scrollbar when not needed [#13253](https://github.com/jupyterlab/jupyterlab/pull/13253) ([@krassowski](https://github.com/krassowski)) +- Added scroll to Running Panel [#13241](https://github.com/jupyterlab/jupyterlab/pull/13241) ([@kulsoomzahra](https://github.com/kulsoomzahra)) +- Removes triggering an event when replacing pasted text [#13230](https://github.com/jupyterlab/jupyterlab/pull/13230) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix cell deletion error message [#13201](https://github.com/jupyterlab/jupyterlab/pull/13201) ([@trungleduc](https://github.com/trungleduc)) +- Use keystroke format consistent with menus [#13200](https://github.com/jupyterlab/jupyterlab/pull/13200) ([@fcollonval](https://github.com/fcollonval)) +- Add a title to the RTC panel [#13196](https://github.com/jupyterlab/jupyterlab/pull/13196) ([@jtpio](https://github.com/jtpio)) +- Fix removing out of view cells [#13194](https://github.com/jupyterlab/jupyterlab/pull/13194) ([@fcollonval](https://github.com/fcollonval)) +- Fix JSON viewer syntax highlighting [#13183](https://github.com/jupyterlab/jupyterlab/pull/13183) ([@jtpio](https://github.com/jtpio)) +- Always show tooltip in hover box even if edges are out of view [#13161](https://github.com/jupyterlab/jupyterlab/pull/13161) ([@krassowski](https://github.com/krassowski)) +- Allow empty notebook [#13141](https://github.com/jupyterlab/jupyterlab/pull/13141) ([@hbcarlos](https://github.com/hbcarlos)) +- Stop observing size disposed widget [#13137](https://github.com/jupyterlab/jupyterlab/pull/13137) ([@fcollonval](https://github.com/fcollonval)) +- Resolve core_path before calling nodejs [#13126](https://github.com/jupyterlab/jupyterlab/pull/13126) ([@fcollonval](https://github.com/fcollonval)) +- Pin jupyter_ydoc to 0.2 [#13124](https://github.com/jupyterlab/jupyterlab/pull/13124) ([@hbcarlos](https://github.com/hbcarlos)) +- Avoid menus overflowing in small screens [#13109](https://github.com/jupyterlab/jupyterlab/pull/13109) ([@steff456](https://github.com/steff456)) +- Fallback to local yarn version if jlpm does not exist [#13104](https://github.com/jupyterlab/jupyterlab/pull/13104) ([@fcollonval](https://github.com/fcollonval)) +- Switch back to `display` to hide tabs [#13103](https://github.com/jupyterlab/jupyterlab/pull/13103) ([@fcollonval](https://github.com/fcollonval)) +- Preserve kernel icon aspect ratio [#13090](https://github.com/jupyterlab/jupyterlab/pull/13090) ([@fcollonval](https://github.com/fcollonval)) +- Added mimeType for .webp image files [#13066](https://github.com/jupyterlab/jupyterlab/pull/13066) ([@alec-kr](https://github.com/alec-kr)) +- Fix cell toolbar layout [#13059](https://github.com/jupyterlab/jupyterlab/pull/13059) ([@kulsoomzahra](https://github.com/kulsoomzahra)) +- Keep completer visible when anchor is horizontally scrolled out of view [#13046](https://github.com/jupyterlab/jupyterlab/pull/13046) ([@krassowski](https://github.com/krassowski)) +- Reorder of webpackConfig merge [#13040](https://github.com/jupyterlab/jupyterlab/pull/13040) ([@matthewturk](https://github.com/matthewturk)) +- Update Python icon to be PSF Trademark compliant [#13035](https://github.com/jupyterlab/jupyterlab/pull/13035) ([@ajbozarth](https://github.com/ajbozarth)) +- Support stateStorage for API calls [#13015](https://github.com/jupyterlab/jupyterlab/pull/13015) ([@fcollonval](https://github.com/fcollonval)) +- Conditional call to waitIsReady in reload [#13011](https://github.com/jupyterlab/jupyterlab/pull/13011) ([@fcollonval](https://github.com/fcollonval)) +- update xterm.js dependency [#12974](https://github.com/jupyterlab/jupyterlab/pull/12974) ([@athornton](https://github.com/athornton)) +- Add scrolling to `debugger` variable renderer [#12968](https://github.com/jupyterlab/jupyterlab/pull/12968) ([@firai](https://github.com/firai)) +- Fix resizing and selection of debugger variable explorer grid [#12943](https://github.com/jupyterlab/jupyterlab/pull/12943) ([@firai](https://github.com/firai)) +- Only show "Shut Down Kernel" if kernel is running [#12919](https://github.com/jupyterlab/jupyterlab/pull/12919) ([@krassowski](https://github.com/krassowski)) +- Bump jupyter_server_ydoc>=0.1.9 [#12876](https://github.com/jupyterlab/jupyterlab/pull/12876) ([@davidbrochart](https://github.com/davidbrochart)) +- Fix progress bar not working after uploading multiple files finished [#12871](https://github.com/jupyterlab/jupyterlab/pull/12871) ([@hsuanxyz](https://github.com/hsuanxyz)) +- Fix kernel in the statusbar does not match the actual [#12865](https://github.com/jupyterlab/jupyterlab/pull/12865) ([@hsuanxyz](https://github.com/hsuanxyz)) +- Store Y updates [#12852](https://github.com/jupyterlab/jupyterlab/pull/12852) ([@davidbrochart](https://github.com/davidbrochart)) +- Fixes renaming files from title while using a custom drive [#12849](https://github.com/jupyterlab/jupyterlab/pull/12849) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix CI failures [#12843](https://github.com/jupyterlab/jupyterlab/pull/12843) ([@fcollonval](https://github.com/fcollonval)) +- Adjust css to not leave trace of deleted widgets [#12838](https://github.com/jupyterlab/jupyterlab/pull/12838) ([@thomasaarholt](https://github.com/thomasaarholt)) +- Remove drive prefix from the file path when creating the new path [#12824](https://github.com/jupyterlab/jupyterlab/pull/12824) ([@hbcarlos](https://github.com/hbcarlos)) +- Use path to extract `tmpPath` [#12823](https://github.com/jupyterlab/jupyterlab/pull/12823) ([@fcollonval](https://github.com/fcollonval)) +- Robuster UI tests [#12821](https://github.com/jupyterlab/jupyterlab/pull/12821) ([@fcollonval](https://github.com/fcollonval)) +- Fix workspace URL while cloning a workspace [#12794](https://github.com/jupyterlab/jupyterlab/pull/12794) ([@aditya211935](https://github.com/aditya211935)) +- update tab name after file rename [#12791](https://github.com/jupyterlab/jupyterlab/pull/12791) ([@RobbyPratl](https://github.com/RobbyPratl)) +- Update base.css [#12783](https://github.com/jupyterlab/jupyterlab/pull/12783) ([@siddartha-10](https://github.com/siddartha-10)) +- Updates ydoc [#12779](https://github.com/jupyterlab/jupyterlab/pull/12779) ([@hbcarlos](https://github.com/hbcarlos)) +- Debugger: Fix CSS for variables inspecting [#12749](https://github.com/jupyterlab/jupyterlab/pull/12749) ([@martinRenou](https://github.com/martinRenou)) +- Fix staging/yarn.lock registry [#12742](https://github.com/jupyterlab/jupyterlab/pull/12742) ([@vidartf](https://github.com/vidartf)) +- Set focus when active cell changes only from mouse click [#12735](https://github.com/jupyterlab/jupyterlab/pull/12735) ([@fcollonval](https://github.com/fcollonval)) +- Translate "Default: " and "Remove" in custom fields [#12732](https://github.com/jupyterlab/jupyterlab/pull/12732) ([@krassowski](https://github.com/krassowski)) +- Fix cell toolbar overlap in side-by-side render mode [#12710](https://github.com/jupyterlab/jupyterlab/pull/12710) ([@peytondmurray](https://github.com/peytondmurray)) +- Split the Document Manager extension into multiple plugins [#12701](https://github.com/jupyterlab/jupyterlab/pull/12701) ([@jtpio](https://github.com/jtpio)) +- Fix arrow position on unrendered markdown cell [#12650](https://github.com/jupyterlab/jupyterlab/pull/12650) ([@fcollonval](https://github.com/fcollonval)) +- Fix kernel protocol serialization [#12619](https://github.com/jupyterlab/jupyterlab/pull/12619) ([@davidbrochart](https://github.com/davidbrochart)) +- Break loop activeCell -> activeHeading [#12612](https://github.com/jupyterlab/jupyterlab/pull/12612) ([@fcollonval](https://github.com/fcollonval)) -### Maintenance and upkeep improvements +#### Maintenance and upkeep improvements + +- Bump lumino to 2.1.1 [#14447](https://github.com/jupyterlab/jupyterlab/pull/14447) ([@fcollonval](https://github.com/fcollonval)) +- Update jupyter-lsp schema [#14430](https://github.com/jupyterlab/jupyterlab/pull/14430) ([@krassowski](https://github.com/krassowski)) +- Fix documentation build on CI [#14423](https://github.com/jupyterlab/jupyterlab/pull/14423) ([@jtpio](https://github.com/jtpio)) +- Fix CI: remove/update broken docs links [#14414](https://github.com/jupyterlab/jupyterlab/pull/14414) ([@krassowski](https://github.com/krassowski)) +- Upgrade all `@codemirror` and `@lezer` packages to latest [#14413](https://github.com/jupyterlab/jupyterlab/pull/14413) ([@krassowski](https://github.com/krassowski)) +- Fix run-cells snapshot [#14388](https://github.com/jupyterlab/jupyterlab/pull/14388) ([@krassowski](https://github.com/krassowski)) +- Do not override snapshots between update runs [#14381](https://github.com/jupyterlab/jupyterlab/pull/14381) ([@krassowski](https://github.com/krassowski)) +- Upgrade dependencies [#14339](https://github.com/jupyterlab/jupyterlab/pull/14339) ([@fcollonval](https://github.com/fcollonval)) +- Upgrade @jupyter/ydoc [#14334](https://github.com/jupyterlab/jupyterlab/pull/14334) ([@fcollonval](https://github.com/fcollonval)) +- Update to Playwright 1.32 [#14323](https://github.com/jupyterlab/jupyterlab/pull/14323) ([@jtpio](https://github.com/jtpio)) +- Bump ipython from 8.11.0 to 8.12.0 [#14316](https://github.com/jupyterlab/jupyterlab/pull/14316) ([@dependabot](https://github.com/dependabot)) +- Bump ipywidgets from 8.0.4 to 8.0.6 [#14315](https://github.com/jupyterlab/jupyterlab/pull/14315) ([@dependabot](https://github.com/dependabot)) +- Bump jupyterlab-language-pack-zh-cn from 3.6.post0 to 3.6.post1 [#14314](https://github.com/jupyterlab/jupyterlab/pull/14314) ([@dependabot](https://github.com/dependabot)) +- Bump black\[jupyter\] from 23.1.0 to 23.3.0 [#14313](https://github.com/jupyterlab/jupyterlab/pull/14313) ([@dependabot](https://github.com/dependabot)) +- Bump ruff from 0.0.255 to 0.0.260 [#14312](https://github.com/jupyterlab/jupyterlab/pull/14312) ([@dependabot](https://github.com/dependabot)) +- Bump actions/stale from 7 to 8 [#14311](https://github.com/jupyterlab/jupyterlab/pull/14311) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.7.0 to 35.7.8 [#14310](https://github.com/jupyterlab/jupyterlab/pull/14310) ([@dependabot](https://github.com/dependabot)) +- Be tolerant on map changes in UI test [#14302](https://github.com/jupyterlab/jupyterlab/pull/14302) ([@fcollonval](https://github.com/fcollonval)) +- Add context for translatable strings to avoid clash with 3.x [#14297](https://github.com/jupyterlab/jupyterlab/pull/14297) ([@fcollonval](https://github.com/fcollonval)) +- Add missing lumino package as singleton [#14287](https://github.com/jupyterlab/jupyterlab/pull/14287) ([@fcollonval](https://github.com/fcollonval)) +- Add `--skip-dev-build`, use with `yarn` invocation to fix binder [#14273](https://github.com/jupyterlab/jupyterlab/pull/14273) ([@bollwyvl](https://github.com/bollwyvl)) +- Fix failing `check_links` job [#14243](https://github.com/jupyterlab/jupyterlab/pull/14243) ([@krassowski](https://github.com/krassowski)) +- Enforce a minimal set of CSS selector complexity rules [#14238](https://github.com/jupyterlab/jupyterlab/pull/14238) ([@krassowski](https://github.com/krassowski)) +- Specify peerDependencies to remove yarn warning [#14230](https://github.com/jupyterlab/jupyterlab/pull/14230) ([@fcollonval](https://github.com/fcollonval)) +- Update ESLint dependencies [#14216](https://github.com/jupyterlab/jupyterlab/pull/14216) ([@jtpio](https://github.com/jtpio)) +- Update to TypeScript 5 final [#14215](https://github.com/jupyterlab/jupyterlab/pull/14215) ([@jtpio](https://github.com/jtpio)) +- Fix 'completer with doc panel' UI test [#14214](https://github.com/jupyterlab/jupyterlab/pull/14214) ([@brichet](https://github.com/brichet)) +- Upgrade to lumino 2 final [#14201](https://github.com/jupyterlab/jupyterlab/pull/14201) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 35.6.1 to 35.7.0 [#14191](https://github.com/jupyterlab/jupyterlab/pull/14191) ([@dependabot](https://github.com/dependabot)) +- Update `webpack` dependencies [#14189](https://github.com/jupyterlab/jupyterlab/pull/14189) ([@jtpio](https://github.com/jtpio)) +- Remove shebang from non-executable script node-version-check.js [#14181](https://github.com/jupyterlab/jupyterlab/pull/14181) ([@frenzymadness](https://github.com/frenzymadness)) +- Remove deprecated code [#14160](https://github.com/jupyterlab/jupyterlab/pull/14160) ([@fcollonval](https://github.com/fcollonval)) +- Clean up events service types in preparation for release [#14149](https://github.com/jupyterlab/jupyterlab/pull/14149) ([@afshin](https://github.com/afshin)) +- Update to Lumino 2 RC 1 [#14146](https://github.com/jupyterlab/jupyterlab/pull/14146) ([@jtpio](https://github.com/jtpio)) +- Switch to monthly dependabot update [#14144](https://github.com/jupyterlab/jupyterlab/pull/14144) ([@fcollonval](https://github.com/fcollonval)) +- Bump ruff from 0.0.253 to 0.0.254 [#14137](https://github.com/jupyterlab/jupyterlab/pull/14137) ([@dependabot](https://github.com/dependabot)) +- Bump ipython from 8.10.0 to 8.11.0 [#14136](https://github.com/jupyterlab/jupyterlab/pull/14136) ([@dependabot](https://github.com/dependabot)) +- Bump matplotlib from 3.7.0 to 3.7.1 [#14135](https://github.com/jupyterlab/jupyterlab/pull/14135) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.6.0 to 35.6.1 [#14134](https://github.com/jupyterlab/jupyterlab/pull/14134) ([@dependabot](https://github.com/dependabot)) +- Use upstream `Stream` instead of downstream stream [#14123](https://github.com/jupyterlab/jupyterlab/pull/14123) ([@afshin](https://github.com/afshin)) +- Bump vega from 5.22.1 to 5.23.0 [#14119](https://github.com/jupyterlab/jupyterlab/pull/14119) ([@dependabot](https://github.com/dependabot)) +- Update to TypeScript 5.0 RC [#14114](https://github.com/jupyterlab/jupyterlab/pull/14114) ([@jtpio](https://github.com/jtpio)) +- Bump ruff from 0.0.249 to 0.0.252 [#14100](https://github.com/jupyterlab/jupyterlab/pull/14100) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.5.5 to 35.6.0 [#14099](https://github.com/jupyterlab/jupyterlab/pull/14099) ([@dependabot](https://github.com/dependabot)) +- Bump to Lumino 2.0.0-rc.0 [#14096](https://github.com/jupyterlab/jupyterlab/pull/14096) ([@fcollonval](https://github.com/fcollonval)) +- Enable `--extensions-in-dev-mode` on Gitpod [#14076](https://github.com/jupyterlab/jupyterlab/pull/14076) ([@jtpio](https://github.com/jtpio)) +- Update to Playwright 1.31.0 [#14067](https://github.com/jupyterlab/jupyterlab/pull/14067) ([@jtpio](https://github.com/jtpio)) +- Install collaboration package on binder [#14061](https://github.com/jupyterlab/jupyterlab/pull/14061) ([@fcollonval](https://github.com/fcollonval)) +- Bump scipy from 1.10.0 to 1.10.1 [#14051](https://github.com/jupyterlab/jupyterlab/pull/14051) ([@dependabot](https://github.com/dependabot)) +- Bump matplotlib from 3.6.3 to 3.7.0 [#14050](https://github.com/jupyterlab/jupyterlab/pull/14050) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.5.2 to 35.5.5 [#14048](https://github.com/jupyterlab/jupyterlab/pull/14048) ([@dependabot](https://github.com/dependabot)) +- Increases timeout [#14045](https://github.com/jupyterlab/jupyterlab/pull/14045) ([@brichet](https://github.com/brichet)) +- Fix JupyterLab command on Gitpod [#14043](https://github.com/jupyterlab/jupyterlab/pull/14043) ([@jtpio](https://github.com/jtpio)) +- Get dev binder up and running again [#14038](https://github.com/jupyterlab/jupyterlab/pull/14038) ([@bollwyvl](https://github.com/bollwyvl)) +- Lazy load `@lumino/datagrid` [#14037](https://github.com/jupyterlab/jupyterlab/pull/14037) ([@bollwyvl](https://github.com/bollwyvl)) +- Update react-json-tree, replace react-highlighter with react-highlight-words [#14034](https://github.com/jupyterlab/jupyterlab/pull/14034) ([@bollwyvl](https://github.com/bollwyvl)) +- Increase galata update timeouts [#13985](https://github.com/jupyterlab/jupyterlab/pull/13985) ([@krassowski](https://github.com/krassowski)) +- Use node 18 for benchmark [#13982](https://github.com/jupyterlab/jupyterlab/pull/13982) ([@fcollonval](https://github.com/fcollonval)) +- Add back `@types/react` as a dependency of `@jupyterlab/apputils` [#13981](https://github.com/jupyterlab/jupyterlab/pull/13981) ([@jtpio](https://github.com/jtpio)) +- Bump ruff from 0.0.242 to 0.0.246 [#13980](https://github.com/jupyterlab/jupyterlab/pull/13980) ([@dependabot](https://github.com/dependabot)) +- Bump jupyterlab-language-pack-zh-cn from 3.5.post4 to 3.6.post0 [#13979](https://github.com/jupyterlab/jupyterlab/pull/13979) ([@dependabot](https://github.com/dependabot)) +- Bump ipython from 8.9.0 to 8.10.0 [#13978](https://github.com/jupyterlab/jupyterlab/pull/13978) ([@dependabot](https://github.com/dependabot)) +- Bump actions/cache from 2 to 3 [#13977](https://github.com/jupyterlab/jupyterlab/pull/13977) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.5.0 to 35.5.2 [#13976](https://github.com/jupyterlab/jupyterlab/pull/13976) ([@dependabot](https://github.com/dependabot)) +- Relax memory-leak action [#13974](https://github.com/jupyterlab/jupyterlab/pull/13974) ([@fcollonval](https://github.com/fcollonval)) +- Fix yarn.lock [#13963](https://github.com/jupyterlab/jupyterlab/pull/13963) ([@fcollonval](https://github.com/fcollonval)) +- Fix verdaccio start up with nodejs 18.14.0 [#13959](https://github.com/jupyterlab/jupyterlab/pull/13959) ([@fcollonval](https://github.com/fcollonval)) +- Remove rtc documentation [#13952](https://github.com/jupyterlab/jupyterlab/pull/13952) ([@hbcarlos](https://github.com/hbcarlos)) +- Report benchmark status even in case of failure [#13950](https://github.com/jupyterlab/jupyterlab/pull/13950) ([@fcollonval](https://github.com/fcollonval)) +- Remove vdom packages [#13949](https://github.com/jupyterlab/jupyterlab/pull/13949) ([@fcollonval](https://github.com/fcollonval)) +- Import directly from jupyter_server [#13942](https://github.com/jupyterlab/jupyterlab/pull/13942) ([@fcollonval](https://github.com/fcollonval)) +- Use Python 3.11 for js-debugger tests [#13941](https://github.com/jupyterlab/jupyterlab/pull/13941) ([@fcollonval](https://github.com/fcollonval)) +- Update plugin name to `@jupyterlab/filebrowser-extension:default-file-browser` [#13936](https://github.com/jupyterlab/jupyterlab/pull/13936) ([@jtpio](https://github.com/jtpio)) +- Bump ipython from 8.0.0 to 8.9.0 [#13935](https://github.com/jupyterlab/jupyterlab/pull/13935) ([@dependabot](https://github.com/dependabot)) +- Bump black\[jupyter\] from 22.12.0 to 23.1.0 [#13934](https://github.com/jupyterlab/jupyterlab/pull/13934) ([@dependabot](https://github.com/dependabot)) +- Bump ruff from 0.0.238 to 0.0.241 [#13933](https://github.com/jupyterlab/jupyterlab/pull/13933) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.4.4 to 35.5.0 [#13932](https://github.com/jupyterlab/jupyterlab/pull/13932) ([@dependabot](https://github.com/dependabot)) +- Fix UI tests [#13931](https://github.com/jupyterlab/jupyterlab/pull/13931) ([@fcollonval](https://github.com/fcollonval)) +- Upgrade to TypeScript 5.0 beta [#13925](https://github.com/jupyterlab/jupyterlab/pull/13925) ([@jasongrout](https://github.com/jasongrout)) +- Bump http-cache-semantics from 4.1.0 to 4.1.1 [#13922](https://github.com/jupyterlab/jupyterlab/pull/13922) ([@dependabot](https://github.com/dependabot)) +- Rename `@jupyterlab/completer-extension:tracker` to `@jupyterlab/completer-extension:manager` [#13910](https://github.com/jupyterlab/jupyterlab/pull/13910) ([@fcollonval](https://github.com/fcollonval)) +- Improve Galata [#13909](https://github.com/jupyterlab/jupyterlab/pull/13909) ([@fcollonval](https://github.com/fcollonval)) +- Lint fixes [#13905](https://github.com/jupyterlab/jupyterlab/pull/13905) ([@JasonWeill](https://github.com/JasonWeill)) +- Switch to VEGALITE5_MIME_TYPE [#13893](https://github.com/jupyterlab/jupyterlab/pull/13893) ([@ChristopherDavisUCI](https://github.com/ChristopherDavisUCI)) +- Bump altair from 4.2.0 to 4.2.2 [#13892](https://github.com/jupyterlab/jupyterlab/pull/13892) ([@dependabot](https://github.com/dependabot)) +- Add more linting [#13882](https://github.com/jupyterlab/jupyterlab/pull/13882) ([@blink1073](https://github.com/blink1073)) +- upgrade to MathJax 3 \[with git history\] [#13877](https://github.com/jupyterlab/jupyterlab/pull/13877) ([@dlqqq](https://github.com/dlqqq)) +- Upgrade `jlpm` to yarn 3.4.1 [#13875](https://github.com/jupyterlab/jupyterlab/pull/13875) ([@brichet](https://github.com/brichet)) +- Update to Playwright 1.30 [#13871](https://github.com/jupyterlab/jupyterlab/pull/13871) ([@jtpio](https://github.com/jtpio)) +- Update `jupyter_server_ydoc` as 0.6.2 is yanked [#13864](https://github.com/jupyterlab/jupyterlab/pull/13864) ([@fcollonval](https://github.com/fcollonval)) +- Bump jupyterlab-language-pack-zh-cn from 3.2.post7 to 3.5.post4 [#13843](https://github.com/jupyterlab/jupyterlab/pull/13843) ([@dependabot](https://github.com/dependabot)) +- Bump ruff from 0.0.226 to 0.0.230 [#13842](https://github.com/jupyterlab/jupyterlab/pull/13842) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.4.3 to 35.4.4 [#13840](https://github.com/jupyterlab/jupyterlab/pull/13840) ([@dependabot](https://github.com/dependabot)) +- Bump lumino packages to `2.0.0-beta.0` [#13828](https://github.com/jupyterlab/jupyterlab/pull/13828) ([@krassowski](https://github.com/krassowski)) +- Bump matplotlib from 3.5.1 to 3.6.3 [#13821](https://github.com/jupyterlab/jupyterlab/pull/13821) ([@dependabot](https://github.com/dependabot)) +- Bump ipywidgets from 7.6.6 to 8.0.4 [#13820](https://github.com/jupyterlab/jupyterlab/pull/13820) ([@dependabot](https://github.com/dependabot)) +- Bump ruff from 0.0.177 to 0.0.226 [#13819](https://github.com/jupyterlab/jupyterlab/pull/13819) ([@dependabot](https://github.com/dependabot)) +- Bump scipy from 1.7.3 to 1.10.0 [#13818](https://github.com/jupyterlab/jupyterlab/pull/13818) ([@dependabot](https://github.com/dependabot)) +- Bump pandas from 1.3.5 to 1.5.3 [#13817](https://github.com/jupyterlab/jupyterlab/pull/13817) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.4.1 to 35.4.3 [#13816](https://github.com/jupyterlab/jupyterlab/pull/13816) ([@dependabot](https://github.com/dependabot)) +- Remove debug print in test [#13814](https://github.com/jupyterlab/jupyterlab/pull/13814) ([@fcollonval](https://github.com/fcollonval)) +- Clean examples [#13812](https://github.com/jupyterlab/jupyterlab/pull/13812) ([@fcollonval](https://github.com/fcollonval)) +- Dependabot alert on json5 [#13808](https://github.com/jupyterlab/jupyterlab/pull/13808) ([@fcollonval](https://github.com/fcollonval)) +- Dependabot alert on jsonwebtoken [#13807](https://github.com/jupyterlab/jupyterlab/pull/13807) ([@fcollonval](https://github.com/fcollonval)) +- Fix `preferred_dir` for examples [#13788](https://github.com/jupyterlab/jupyterlab/pull/13788) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 35.4.0 to 35.4.1 [#13785](https://github.com/jupyterlab/jupyterlab/pull/13785) ([@dependabot](https://github.com/dependabot)) +- Bump canvas to version with nodejs 18 binaries [#13783](https://github.com/jupyterlab/jupyterlab/pull/13783) ([@fcollonval](https://github.com/fcollonval)) +- Added config to link ts source maps [#13765](https://github.com/jupyterlab/jupyterlab/pull/13765) ([@3coins](https://github.com/3coins)) +- Drop support for Python 3.7 [#13745](https://github.com/jupyterlab/jupyterlab/pull/13745) ([@jtpio](https://github.com/jtpio)) +- Drop the dependency on `@jupyterlab/buildutils` in `@jupyterlab/builder` [#13741](https://github.com/jupyterlab/jupyterlab/pull/13741) ([@jtpio](https://github.com/jtpio)) +- Bump toshimaru/auto-author-assign from 1.6.1 to 1.6.2 [#13738](https://github.com/jupyterlab/jupyterlab/pull/13738) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.2.1 to 35.4.0 [#13737](https://github.com/jupyterlab/jupyterlab/pull/13737) ([@dependabot](https://github.com/dependabot)) +- Upgrades Python to 3.10, Node to 18 [#13722](https://github.com/jupyterlab/jupyterlab/pull/13722) ([@JasonWeill](https://github.com/JasonWeill)) +- Require `jupyter_server>=2.0.1,<3` [#13718](https://github.com/jupyterlab/jupyterlab/pull/13718) ([@jtpio](https://github.com/jtpio)) +- Fix environment activation on Gitpod [#13715](https://github.com/jupyterlab/jupyterlab/pull/13715) ([@jtpio](https://github.com/jtpio)) +- Update copyright date to 2023 in the about dialog [#13708](https://github.com/jupyterlab/jupyterlab/pull/13708) ([@jtpio](https://github.com/jtpio)) +- Updates documentation snapshots [#13706](https://github.com/jupyterlab/jupyterlab/pull/13706) ([@brichet](https://github.com/brichet)) +- Use `DocumentWidgetOpenerMock` [#13703](https://github.com/jupyterlab/jupyterlab/pull/13703) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 35.1.0 to 35.2.1 [#13692](https://github.com/jupyterlab/jupyterlab/pull/13692) ([@dependabot](https://github.com/dependabot)) +- Remove empty button in the notebook toolbar [#13691](https://github.com/jupyterlab/jupyterlab/pull/13691) ([@trungleduc](https://github.com/trungleduc)) +- Bump json5 from 2.2.1 to 2.2.2 [#13681](https://github.com/jupyterlab/jupyterlab/pull/13681) ([@dependabot](https://github.com/dependabot)) +- Bump actions/stale from 6 to 7 [#13666](https://github.com/jupyterlab/jupyterlab/pull/13666) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 35.0.1 to 35.1.0 [#13665](https://github.com/jupyterlab/jupyterlab/pull/13665) ([@dependabot](https://github.com/dependabot)) +- Remove empty license field in pyproject.toml [#13654](https://github.com/jupyterlab/jupyterlab/pull/13654) ([@jtpio](https://github.com/jtpio)) +- Revert "Write the browser open files for test" [#13640](https://github.com/jupyterlab/jupyterlab/pull/13640) ([@fcollonval](https://github.com/fcollonval)) +- Remove `skipLibCheck` in the `vega5-extension` package [#13630](https://github.com/jupyterlab/jupyterlab/pull/13630) ([@jtpio](https://github.com/jtpio)) +- Update to lerna 6.2.0 [#13628](https://github.com/jupyterlab/jupyterlab/pull/13628) ([@jtpio](https://github.com/jtpio)) +- Remove log file otherwise it is committed [#13627](https://github.com/jupyterlab/jupyterlab/pull/13627) ([@fcollonval](https://github.com/fcollonval)) +- Use git command instead of GitHub action [#13625](https://github.com/jupyterlab/jupyterlab/pull/13625) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 34.5.3 to 35.0.1 [#13620](https://github.com/jupyterlab/jupyterlab/pull/13620) ([@dependabot](https://github.com/dependabot)) +- Remove old completer API [#13615](https://github.com/jupyterlab/jupyterlab/pull/13615) ([@krassowski](https://github.com/krassowski)) +- Update to Playwright 1.29 [#13612](https://github.com/jupyterlab/jupyterlab/pull/13612) ([@jtpio](https://github.com/jtpio)) +- Bump react 18 [#13607](https://github.com/jupyterlab/jupyterlab/pull/13607) ([@brichet](https://github.com/brichet)) +- Remove old editor user caret widget (dead code) and selection style [#13586](https://github.com/jupyterlab/jupyterlab/pull/13586) ([@fcollonval](https://github.com/fcollonval)) +- Drop typestyle [#13584](https://github.com/jupyterlab/jupyterlab/pull/13584) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 34.5.0 to 34.5.3 [#13574](https://github.com/jupyterlab/jupyterlab/pull/13574) ([@dependabot](https://github.com/dependabot)) +- Adopt ruff and clean up pre-commit [#13562](https://github.com/jupyterlab/jupyterlab/pull/13562) ([@blink1073](https://github.com/blink1073)) +- Bump dessant/lock-threads from 3 to 4 [#13540](https://github.com/jupyterlab/jupyterlab/pull/13540) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 34.3.0 to 34.5.0 [#13539](https://github.com/jupyterlab/jupyterlab/pull/13539) ([@dependabot](https://github.com/dependabot)) +- Bump decode-uri-component from 0.2.0 to 0.2.2 [#13536](https://github.com/jupyterlab/jupyterlab/pull/13536) ([@dependabot](https://github.com/dependabot)) +- Update `terser-webpack-plugin` [#13532](https://github.com/jupyterlab/jupyterlab/pull/13532) ([@jtpio](https://github.com/jtpio)) +- Fix accessing owner/repo in CI [#13523](https://github.com/jupyterlab/jupyterlab/pull/13523) ([@fcollonval](https://github.com/fcollonval)) +- Comment on the PR once the snapshots have been updated. [#13516](https://github.com/jupyterlab/jupyterlab/pull/13516) ([@fcollonval](https://github.com/fcollonval)) +- Fix for pytest-jupyter 0.5.2+ [#13515](https://github.com/jupyterlab/jupyterlab/pull/13515) ([@fcollonval](https://github.com/fcollonval)) +- Bump sanitize-html to 2.7.3 [#13509](https://github.com/jupyterlab/jupyterlab/pull/13509) ([@fcollonval](https://github.com/fcollonval)) +- Fix Python test dependencies [#13508](https://github.com/jupyterlab/jupyterlab/pull/13508) ([@fcollonval](https://github.com/fcollonval)) +- Depend on `@jupyter/ydoc` instead of `@jupyter-notebook/ydoc` [#13506](https://github.com/jupyterlab/jupyterlab/pull/13506) ([@jtpio](https://github.com/jtpio)) +- Require jupyter-server-ydoc >=0.5.1 [#13478](https://github.com/jupyterlab/jupyterlab/pull/13478) ([@davidbrochart](https://github.com/davidbrochart)) +- Test against Python 3.11 [#13474](https://github.com/jupyterlab/jupyterlab/pull/13474) ([@fcollonval](https://github.com/fcollonval)) +- Drop the `moment` dependency [#13469](https://github.com/jupyterlab/jupyterlab/pull/13469) ([@jtpio](https://github.com/jtpio)) +- Force right sidebar size [#13447](https://github.com/jupyterlab/jupyterlab/pull/13447) ([@fcollonval](https://github.com/fcollonval)) +- Use default URL in test mock-up [#13443](https://github.com/jupyterlab/jupyterlab/pull/13443) ([@fcollonval](https://github.com/fcollonval)) +- Require jupyter_server_ydoc >=0.4.0 [#13434](https://github.com/jupyterlab/jupyterlab/pull/13434) ([@davidbrochart](https://github.com/davidbrochart)) +- Clean up and update dependencies [#13430](https://github.com/jupyterlab/jupyterlab/pull/13430) ([@fcollonval](https://github.com/fcollonval)) +- Use more consistent naming for user service [#13428](https://github.com/jupyterlab/jupyterlab/pull/13428) ([@fcollonval](https://github.com/fcollonval)) +- Remove shared-model from labeler [#13422](https://github.com/jupyterlab/jupyterlab/pull/13422) ([@fcollonval](https://github.com/fcollonval)) +- tomllib is in stdlib in Python 3.11+ [#13399](https://github.com/jupyterlab/jupyterlab/pull/13399) ([@frenzymadness](https://github.com/frenzymadness)) +- Bump loader-utils from 1.4.0 to 1.4.1 [#13396](https://github.com/jupyterlab/jupyterlab/pull/13396) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 34.0.2 to 34.3.0 [#13391](https://github.com/jupyterlab/jupyterlab/pull/13391) ([@dependabot](https://github.com/dependabot)) +- Add jupyter-server-fileid to Binder [#13370](https://github.com/jupyterlab/jupyterlab/pull/13370) ([@fcollonval](https://github.com/fcollonval)) +- Integrity check does not clean style import when emptied [#13367](https://github.com/jupyterlab/jupyterlab/pull/13367) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 33.0.0 to 34.0.2 [#13355](https://github.com/jupyterlab/jupyterlab/pull/13355) ([@dependabot](https://github.com/dependabot)) +- Export return type of a public method [#13354](https://github.com/jupyterlab/jupyterlab/pull/13354) ([@fcollonval](https://github.com/fcollonval)) +- Check a core path is actually a package [#13346](https://github.com/jupyterlab/jupyterlab/pull/13346) ([@fcollonval](https://github.com/fcollonval)) +- Fix Binder for jupyter-server v2 [#13344](https://github.com/jupyterlab/jupyterlab/pull/13344) ([@fcollonval](https://github.com/fcollonval)) +- Fix the examples with jupyter-server v2 [#13336](https://github.com/jupyterlab/jupyterlab/pull/13336) ([@fcollonval](https://github.com/fcollonval)) +- Add mdformat plugins [#13335](https://github.com/jupyterlab/jupyterlab/pull/13335) ([@blink1073](https://github.com/blink1073)) +- Removes empty requires list [#13334](https://github.com/jupyterlab/jupyterlab/pull/13334) ([@hbcarlos](https://github.com/hbcarlos)) +- Switch to releaser v2 [#13322](https://github.com/jupyterlab/jupyterlab/pull/13322) ([@blink1073](https://github.com/blink1073)) +- Deprecate managing source extensions with `jupyter labextension` [#13321](https://github.com/jupyterlab/jupyterlab/pull/13321) ([@jtpio](https://github.com/jtpio)) +- Reduce ILayoutRestorer API surface area [#13300](https://github.com/jupyterlab/jupyterlab/pull/13300) ([@afshin](https://github.com/afshin)) +- Fix kernel snapshot in test documentation [#13295](https://github.com/jupyterlab/jupyterlab/pull/13295) ([@brichet](https://github.com/brichet)) +- Bump tj-actions/changed-files from 32.1.2 to 33.0.0 [#13294](https://github.com/jupyterlab/jupyterlab/pull/13294) ([@dependabot](https://github.com/dependabot)) +- Remove `generate_changelog.py` script [#13262](https://github.com/jupyterlab/jupyterlab/pull/13262) ([@jtpio](https://github.com/jtpio)) +- Bump tj-actions/changed-files from 32.0.0 to 32.1.2 [#13260](https://github.com/jupyterlab/jupyterlab/pull/13260) ([@dependabot](https://github.com/dependabot)) +- Check for unused file browser style rules in Galata [#13256](https://github.com/jupyterlab/jupyterlab/pull/13256) ([@krassowski](https://github.com/krassowski)) +- Update to lerna 6 [#13251](https://github.com/jupyterlab/jupyterlab/pull/13251) ([@jtpio](https://github.com/jtpio)) +- Fix documentation snapshot [#13244](https://github.com/jupyterlab/jupyterlab/pull/13244) ([@fcollonval](https://github.com/fcollonval)) +- Enable RTC by default when starting JL in the Gitpod setup [#13239](https://github.com/jupyterlab/jupyterlab/pull/13239) ([@firai](https://github.com/firai)) +- Bump memory-leak action [#13231](https://github.com/jupyterlab/jupyterlab/pull/13231) ([@fcollonval](https://github.com/fcollonval)) +- Fix memory leaks [#13229](https://github.com/jupyterlab/jupyterlab/pull/13229) ([@fcollonval](https://github.com/fcollonval)) +- Update `pytest` and `pytest-check-links` dependencies [#13219](https://github.com/jupyterlab/jupyterlab/pull/13219) ([@jtpio](https://github.com/jtpio)) +- Remove unused modelDBFactory [#13213](https://github.com/jupyterlab/jupyterlab/pull/13213) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 31.0.3 to 32.0.0 [#13212](https://github.com/jupyterlab/jupyterlab/pull/13212) ([@dependabot](https://github.com/dependabot)) +- Fix typo in the "Test Minimum Version" CI step [#13210](https://github.com/jupyterlab/jupyterlab/pull/13210) ([@jtpio](https://github.com/jtpio)) +- Update to Playwright 1.27 [#13205](https://github.com/jupyterlab/jupyterlab/pull/13205) ([@jtpio](https://github.com/jtpio)) +- Try the GitHub Playwright reporter on CI [#13198](https://github.com/jupyterlab/jupyterlab/pull/13198) ([@jtpio](https://github.com/jtpio)) +- Update RJSF to latest stable version [#13191](https://github.com/jupyterlab/jupyterlab/pull/13191) ([@brichet](https://github.com/brichet)) +- Bump tj-actions/changed-files from 31.0.1 to 31.0.3 [#13171](https://github.com/jupyterlab/jupyterlab/pull/13171) ([@dependabot](https://github.com/dependabot)) +- Remove `width: 100%` of `jp-WindowedPanel-inner` [#13157](https://github.com/jupyterlab/jupyterlab/pull/13157) ([@jtpio](https://github.com/jtpio)) +- Remove `width: 100%` of `jp-WindowedPanel-window` [#13154](https://github.com/jupyterlab/jupyterlab/pull/13154) ([@jtpio](https://github.com/jtpio)) +- Bump lerna [#13147](https://github.com/jupyterlab/jupyterlab/pull/13147) ([@fcollonval](https://github.com/fcollonval)) +- Update to Playwright 1.26 [#13140](https://github.com/jupyterlab/jupyterlab/pull/13140) ([@jtpio](https://github.com/jtpio)) +- Bump tj-actions/changed-files from 29.0.7 to 31.0.1 [#13130](https://github.com/jupyterlab/jupyterlab/pull/13130) ([@dependabot](https://github.com/dependabot)) +- Bump actions/stale from 5 to 6 [#13129](https://github.com/jupyterlab/jupyterlab/pull/13129) ([@dependabot](https://github.com/dependabot)) +- Remove xeus-python installation for debugger test [#13113](https://github.com/jupyterlab/jupyterlab/pull/13113) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 29.0.4 to 29.0.7 [#13106](https://github.com/jupyterlab/jupyterlab/pull/13106) ([@dependabot](https://github.com/dependabot)) +- Revert "Pin hatch-jupyter-builder for now" [#13084](https://github.com/jupyterlab/jupyterlab/pull/13084) ([@fcollonval](https://github.com/fcollonval)) +- Pin hatch-jupyter-builder for now [#13083](https://github.com/jupyterlab/jupyterlab/pull/13083) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 29.0.2 to 29.0.4 [#13079](https://github.com/jupyterlab/jupyterlab/pull/13079) ([@dependabot](https://github.com/dependabot)) +- Remove dead code [#13077](https://github.com/jupyterlab/jupyterlab/pull/13077) ([@fcollonval](https://github.com/fcollonval)) +- Remove noisy log message [#13073](https://github.com/jupyterlab/jupyterlab/pull/13073) ([@fcollonval](https://github.com/fcollonval)) +- Bump to Lumino 2áĩ…âļ [#13062](https://github.com/jupyterlab/jupyterlab/pull/13062) ([@afshin](https://github.com/afshin)) +- Switch to `pull_request_target` to have write permission on forks [#13060](https://github.com/jupyterlab/jupyterlab/pull/13060) ([@fcollonval](https://github.com/fcollonval)) +- Change compilation target from ES2017 to ES2018 [#13053](https://github.com/jupyterlab/jupyterlab/pull/13053) ([@afshin](https://github.com/afshin)) +- Fix GitHub script variable name [#13050](https://github.com/jupyterlab/jupyterlab/pull/13050) ([@fcollonval](https://github.com/fcollonval)) +- REST API is under a namespace in github-script [#13043](https://github.com/jupyterlab/jupyterlab/pull/13043) ([@fcollonval](https://github.com/fcollonval)) +- "Fix License Headers" CI check is failing [#13041](https://github.com/jupyterlab/jupyterlab/pull/13041) ([@fcollonval](https://github.com/fcollonval)) +- Update the Gitpod setup to use `micromamba` to bootstrap the dev environment [#13030](https://github.com/jupyterlab/jupyterlab/pull/13030) ([@jtpio](https://github.com/jtpio)) +- Drop node-fetch for galata helpers [#13029](https://github.com/jupyterlab/jupyterlab/pull/13029) ([@fcollonval](https://github.com/fcollonval)) +- Bump tj-actions/changed-files from 28 to 29.0.2 [#13025](https://github.com/jupyterlab/jupyterlab/pull/13025) ([@dependabot](https://github.com/dependabot)) +- Fix lumino API documentation links [#13021](https://github.com/jupyterlab/jupyterlab/pull/13021) ([@fcollonval](https://github.com/fcollonval)) +- Use `python-version` in the macos workflow [#13014](https://github.com/jupyterlab/jupyterlab/pull/13014) ([@jtpio](https://github.com/jtpio)) +- Remove unneeded cm5 types in examples [#13010](https://github.com/jupyterlab/jupyterlab/pull/13010) ([@fcollonval](https://github.com/fcollonval)) +- Update to Lumino 2 [#12992](https://github.com/jupyterlab/jupyterlab/pull/12992) ([@afshin](https://github.com/afshin)) +- Bump tj-actions/changed-files from 24 to 28 [#12986](https://github.com/jupyterlab/jupyterlab/pull/12986) ([@dependabot](https://github.com/dependabot)) +- Fix copy the reference data for final report [#12984](https://github.com/jupyterlab/jupyterlab/pull/12984) ([@fcollonval](https://github.com/fcollonval)) +- Drop the pin on `jupyterlab_widgets` in the docs dependencies [#12979](https://github.com/jupyterlab/jupyterlab/pull/12979) ([@jtpio](https://github.com/jtpio)) +- Add `(developer)` label to the developer facing commands [#12970](https://github.com/jupyterlab/jupyterlab/pull/12970) ([@jtpio](https://github.com/jtpio)) +- Pin `jupyterlab_widgets==1.1.1` in `docs-screenshots` [#12967](https://github.com/jupyterlab/jupyterlab/pull/12967) ([@jtpio](https://github.com/jtpio)) +- Update documentation welcome image [#12957](https://github.com/jupyterlab/jupyterlab/pull/12957) ([@fcollonval](https://github.com/fcollonval)) +- Fix dependabot alerts for ejs and got [#12956](https://github.com/jupyterlab/jupyterlab/pull/12956) ([@fcollonval](https://github.com/fcollonval)) +- Bump lerna to 5.x [#12950](https://github.com/jupyterlab/jupyterlab/pull/12950) ([@fcollonval](https://github.com/fcollonval)) +- Bump yarn.js to 1.22.19 [#12949](https://github.com/jupyterlab/jupyterlab/pull/12949) ([@fcollonval](https://github.com/fcollonval)) +- Bump toshimaru/auto-author-assign from 1.6.0 to 1.6.1 [#12922](https://github.com/jupyterlab/jupyterlab/pull/12922) ([@dependabot](https://github.com/dependabot)) +- Remove @lumino/coreutils dependency from @jupyterlab/buildutils [#12910](https://github.com/jupyterlab/jupyterlab/pull/12910) ([@afshin](https://github.com/afshin)) +- Log launcher error to console [#12909](https://github.com/jupyterlab/jupyterlab/pull/12909) ([@trungleduc](https://github.com/trungleduc)) +- Add `dev_mode/style.js` to the licenser ignore list [#12902](https://github.com/jupyterlab/jupyterlab/pull/12902) ([@jtpio](https://github.com/jtpio)) +- Add license header fix to git-blame-ignore [#12900](https://github.com/jupyterlab/jupyterlab/pull/12900) ([@fcollonval](https://github.com/fcollonval)) +- Bump toshimaru/auto-author-assign from 1.5.1 to 1.6.0 [#12890](https://github.com/jupyterlab/jupyterlab/pull/12890) ([@dependabot](https://github.com/dependabot)) +- Update `yjs-codemirror.next` [#12880](https://github.com/jupyterlab/jupyterlab/pull/12880) ([@jtpio](https://github.com/jtpio)) +- Add license header fix job [#12872](https://github.com/jupyterlab/jupyterlab/pull/12872) ([@fcollonval](https://github.com/fcollonval)) +- Bump toshimaru/auto-author-assign from 1.5.0 to 1.5.1 [#12854](https://github.com/jupyterlab/jupyterlab/pull/12854) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 23 to 24 [#12853](https://github.com/jupyterlab/jupyterlab/pull/12853) ([@dependabot](https://github.com/dependabot)) +- Run `yarn-deduplicate` on `build:core` [#12850](https://github.com/jupyterlab/jupyterlab/pull/12850) ([@jtpio](https://github.com/jtpio)) +- Update snapshots for challenger commit [#12820](https://github.com/jupyterlab/jupyterlab/pull/12820) ([@fcollonval](https://github.com/fcollonval)) +- Bump terser from 4.8.0 to 4.8.1 [#12818](https://github.com/jupyterlab/jupyterlab/pull/12818) ([@dependabot](https://github.com/dependabot)) +- Update `verdaccio`, start registry on `0.0.0.0` instead of `localhost` [#12799](https://github.com/jupyterlab/jupyterlab/pull/12799) ([@jtpio](https://github.com/jtpio)) +- Run memory-leak tests on PR [#12789](https://github.com/jupyterlab/jupyterlab/pull/12789) ([@fcollonval](https://github.com/fcollonval)) +- Use Vega SVG renderer to drop canvas dependency [#12785](https://github.com/jupyterlab/jupyterlab/pull/12785) ([@fcollonval](https://github.com/fcollonval)) +- Bump moment from 2.29.2 to 2.29.4 [#12781](https://github.com/jupyterlab/jupyterlab/pull/12781) ([@dependabot](https://github.com/dependabot)) +- Bump @lumino/widgets to 1.33.0 [#12777](https://github.com/jupyterlab/jupyterlab/pull/12777) ([@fcollonval](https://github.com/fcollonval)) +- Removes lighthouse and markdown-loader-jest [#12776](https://github.com/jupyterlab/jupyterlab/pull/12776) ([@fcollonval](https://github.com/fcollonval)) +- \[memory-leaks\] Fixes following cell addition analysis [#12774](https://github.com/jupyterlab/jupyterlab/pull/12774) ([@fcollonval](https://github.com/fcollonval)) +- Bump parse-url from 6.0.0 to 6.0.2 [#12773](https://github.com/jupyterlab/jupyterlab/pull/12773) ([@dependabot](https://github.com/dependabot)) +- Move YDocWebSocketHandler to jupyter-server [#12772](https://github.com/jupyterlab/jupyterlab/pull/12772) ([@davidbrochart](https://github.com/davidbrochart)) +- Fix memory leaks [#12750](https://github.com/jupyterlab/jupyterlab/pull/12750) ([@fcollonval](https://github.com/fcollonval)) +- Bump version of `marked` and `@types/marked` [#12747](https://github.com/jupyterlab/jupyterlab/pull/12747) ([@krassowski](https://github.com/krassowski)) +- Bump shell-quote from 1.7.2 to 1.7.3 [#12744](https://github.com/jupyterlab/jupyterlab/pull/12744) ([@dependabot](https://github.com/dependabot)) +- Remove unstubExtensionsSearch [#12738](https://github.com/jupyterlab/jupyterlab/pull/12738) ([@fcollonval](https://github.com/fcollonval)) +- Bump actions/cache from 1 to 3 [#12722](https://github.com/jupyterlab/jupyterlab/pull/12722) ([@dependabot](https://github.com/dependabot)) +- Bump actions/stale from 4 to 5 [#12721](https://github.com/jupyterlab/jupyterlab/pull/12721) ([@dependabot](https://github.com/dependabot)) +- Bump actions/download-artifact from 2 to 3 [#12720](https://github.com/jupyterlab/jupyterlab/pull/12720) ([@dependabot](https://github.com/dependabot)) +- stub extension search in UI test [#12714](https://github.com/jupyterlab/jupyterlab/pull/12714) ([@dlqqq](https://github.com/dlqqq)) +- Update dev dependencies [#12698](https://github.com/jupyterlab/jupyterlab/pull/12698) ([@jtpio](https://github.com/jtpio)) +- Bump actions/github-script from 3.1 to 6 [#12693](https://github.com/jupyterlab/jupyterlab/pull/12693) ([@dependabot](https://github.com/dependabot)) +- Bump tj-actions/changed-files from 18.6 to 23 [#12692](https://github.com/jupyterlab/jupyterlab/pull/12692) ([@dependabot](https://github.com/dependabot)) +- Bump actions/setup-python from 3 to 4 [#12691](https://github.com/jupyterlab/jupyterlab/pull/12691) ([@dependabot](https://github.com/dependabot)) +- Bump pre-commit/action from 2.0.3 to 3.0.0 [#12690](https://github.com/jupyterlab/jupyterlab/pull/12690) ([@dependabot](https://github.com/dependabot)) +- Bump actions/upload-artifact from 2 to 3 [#12689](https://github.com/jupyterlab/jupyterlab/pull/12689) ([@dependabot](https://github.com/dependabot)) +- Update to TypeScript 4.7 [#12683](https://github.com/jupyterlab/jupyterlab/pull/12683) ([@jtpio](https://github.com/jtpio)) +- Drop pre-commit from build dependencies [#12680](https://github.com/jupyterlab/jupyterlab/pull/12680) ([@fcollonval](https://github.com/fcollonval)) +- default to system node version in precommit [#12679](https://github.com/jupyterlab/jupyterlab/pull/12679) ([@dlqqq](https://github.com/dlqqq)) +- Remove scripts linked to test [#12654](https://github.com/jupyterlab/jupyterlab/pull/12654) ([@fcollonval](https://github.com/fcollonval)) +- Update codeql action from v1 to v2 [#12645](https://github.com/jupyterlab/jupyterlab/pull/12645) ([@fcollonval](https://github.com/fcollonval)) +- Update snapshot for the extension manager [#12643](https://github.com/jupyterlab/jupyterlab/pull/12643) ([@jtpio](https://github.com/jtpio)) +- Bump actions/setup-python from 2 to 3 [#12642](https://github.com/jupyterlab/jupyterlab/pull/12642) ([@dependabot](https://github.com/dependabot)) +- Bump actions/checkout from 2 to 3 [#12641](https://github.com/jupyterlab/jupyterlab/pull/12641) ([@dependabot](https://github.com/dependabot)) +- Bump toshimaru/auto-author-assign from 1.3.4 to 1.5.0 [#12640](https://github.com/jupyterlab/jupyterlab/pull/12640) ([@dependabot](https://github.com/dependabot)) +- Bump dessant/lock-threads from 2 to 3 [#12639](https://github.com/jupyterlab/jupyterlab/pull/12639) ([@dependabot](https://github.com/dependabot)) +- Bump actions/setup-node from 2 to 3 [#12638](https://github.com/jupyterlab/jupyterlab/pull/12638) ([@dependabot](https://github.com/dependabot)) +- Bump pre-commit/action from 2.0.0 to 2.0.3 [#12637](https://github.com/jupyterlab/jupyterlab/pull/12637) ([@dependabot](https://github.com/dependabot)) +- Add bot to update github actions and remove codeql temporary fix [#12634](https://github.com/jupyterlab/jupyterlab/pull/12634) ([@fcollonval](https://github.com/fcollonval)) +- Remove unneeded build:all and test config [#12618](https://github.com/jupyterlab/jupyterlab/pull/12618) ([@fcollonval](https://github.com/fcollonval)) + +#### Documentation improvements + +- Add user facing changelog [#14437](https://github.com/jupyterlab/jupyterlab/pull/14437) ([@jtpio](https://github.com/jtpio)) +- Add new release postmortem [#14432](https://github.com/jupyterlab/jupyterlab/pull/14432) ([@jtpio](https://github.com/jtpio)) +- Fix documentation build on CI [#14423](https://github.com/jupyterlab/jupyterlab/pull/14423) ([@jtpio](https://github.com/jtpio)) +- Harmonizes form renderer ids [#14415](https://github.com/jupyterlab/jupyterlab/pull/14415) ([@brichet](https://github.com/brichet)) +- Fix CI: remove/update broken docs links [#14414](https://github.com/jupyterlab/jupyterlab/pull/14414) ([@krassowski](https://github.com/krassowski)) +- Switch to new extension template [#14391](https://github.com/jupyterlab/jupyterlab/pull/14391) ([@fcollonval](https://github.com/fcollonval)) +- Improve JavaScript API documentation [#14367](https://github.com/jupyterlab/jupyterlab/pull/14367) ([@fcollonval](https://github.com/fcollonval)) +- Improve jlpm migration guide [#14362](https://github.com/jupyterlab/jupyterlab/pull/14362) ([@fcollonval](https://github.com/fcollonval)) +- Document plugins and tokens [#14360](https://github.com/jupyterlab/jupyterlab/pull/14360) ([@fcollonval](https://github.com/fcollonval)) +- Document Backwards Compatibility, SemVer and Breaking Changes [#14355](https://github.com/jupyterlab/jupyterlab/pull/14355) ([@ericsnekbytes](https://github.com/ericsnekbytes)) +- Align notebook trust behaviour with trust in classic Notebook [#14345](https://github.com/jupyterlab/jupyterlab/pull/14345) ([@krassowski](https://github.com/krassowski)) +- Fix typo [#14303](https://github.com/jupyterlab/jupyterlab/pull/14303) ([@davidbrochart](https://github.com/davidbrochart)) +- Update extension upgrade script [#14279](https://github.com/jupyterlab/jupyterlab/pull/14279) ([@fcollonval](https://github.com/fcollonval)) +- Remove archived repos from the post release checklist [#14259](https://github.com/jupyterlab/jupyterlab/pull/14259) ([@jtpio](https://github.com/jtpio)) +- Fix failing `check_links` job [#14243](https://github.com/jupyterlab/jupyterlab/pull/14243) ([@krassowski](https://github.com/krassowski)) +- Enforce a minimal set of CSS selector complexity rules [#14238](https://github.com/jupyterlab/jupyterlab/pull/14238) ([@krassowski](https://github.com/krassowski)) +- Add note for jest configuration and JLab 3.6 [#14207](https://github.com/jupyterlab/jupyterlab/pull/14207) ([@fcollonval](https://github.com/fcollonval)) +- Update RELEASE.md to mention the draft GitHub release [#14188](https://github.com/jupyterlab/jupyterlab/pull/14188) ([@jtpio](https://github.com/jtpio)) +- Add the releaser workflows to the repo [#14176](https://github.com/jupyterlab/jupyterlab/pull/14176) ([@jtpio](https://github.com/jtpio)) +- Remove deprecated code [#14160](https://github.com/jupyterlab/jupyterlab/pull/14160) ([@fcollonval](https://github.com/fcollonval)) +- Fixes documentation build [#14104](https://github.com/jupyterlab/jupyterlab/pull/14104) ([@brichet](https://github.com/brichet)) +- Bump to Lumino 2.0.0-rc.0 [#14096](https://github.com/jupyterlab/jupyterlab/pull/14096) ([@fcollonval](https://github.com/fcollonval)) +- Update the Classic Notebook FAQ section in the documentation [#14070](https://github.com/jupyterlab/jupyterlab/pull/14070) ([@jtpio](https://github.com/jtpio)) +- Option to disable the autolink feature [#14068](https://github.com/jupyterlab/jupyterlab/pull/14068) ([@cccs-nik](https://github.com/cccs-nik)) +- Move the file name searcher to the file browser toolbar [#14064](https://github.com/jupyterlab/jupyterlab/pull/14064) ([@jtpio](https://github.com/jtpio)) +- Fix attachments [#14052](https://github.com/jupyterlab/jupyterlab/pull/14052) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix RTC check and documentation [#14047](https://github.com/jupyterlab/jupyterlab/pull/14047) ([@fcollonval](https://github.com/fcollonval)) +- Get dev binder up and running again [#14038](https://github.com/jupyterlab/jupyterlab/pull/14038) ([@bollwyvl](https://github.com/bollwyvl)) +- Using metadataform for default notebooktools [#14026](https://github.com/jupyterlab/jupyterlab/pull/14026) ([@brichet](https://github.com/brichet)) +- Bump ruff from 0.0.242 to 0.0.246 [#13980](https://github.com/jupyterlab/jupyterlab/pull/13980) ([@dependabot](https://github.com/dependabot)) +- Mention how to fix pixman, cairo missing library errors that occur while running tests in readthedocs [#13956](https://github.com/jupyterlab/jupyterlab/pull/13956) ([@andrii-i](https://github.com/andrii-i)) +- Remove rtc documentation [#13952](https://github.com/jupyterlab/jupyterlab/pull/13952) ([@hbcarlos](https://github.com/hbcarlos)) +- Remove vdom packages [#13949](https://github.com/jupyterlab/jupyterlab/pull/13949) ([@fcollonval](https://github.com/fcollonval)) +- Fixes toolbar button for Restart Kernel and Run All [#13939](https://github.com/jupyterlab/jupyterlab/pull/13939) ([@JasonWeill](https://github.com/JasonWeill)) +- Improve Galata [#13909](https://github.com/jupyterlab/jupyterlab/pull/13909) ([@fcollonval](https://github.com/fcollonval)) +- Move RTC packages to an extension [#13907](https://github.com/jupyterlab/jupyterlab/pull/13907) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix minor typo in urls.rst [#13902](https://github.com/jupyterlab/jupyterlab/pull/13902) ([@chbrandt](https://github.com/chbrandt)) +- Add more linting [#13882](https://github.com/jupyterlab/jupyterlab/pull/13882) ([@blink1073](https://github.com/blink1073)) +- upgrade to MathJax 3 \[with git history\] [#13877](https://github.com/jupyterlab/jupyterlab/pull/13877) ([@dlqqq](https://github.com/dlqqq)) +- Upgrade `jlpm` to yarn 3.4.1 [#13875](https://github.com/jupyterlab/jupyterlab/pull/13875) ([@brichet](https://github.com/brichet)) +- Update language-packs workflow [#13874](https://github.com/jupyterlab/jupyterlab/pull/13874) ([@fcollonval](https://github.com/fcollonval)) +- Caret operator in documentation [#13856](https://github.com/jupyterlab/jupyterlab/pull/13856) ([@JasonWeill](https://github.com/JasonWeill)) +- Bump ruff from 0.0.226 to 0.0.230 [#13842](https://github.com/jupyterlab/jupyterlab/pull/13842) ([@dependabot](https://github.com/dependabot)) +- Improves translator API [#13834](https://github.com/jupyterlab/jupyterlab/pull/13834) ([@hbcarlos](https://github.com/hbcarlos)) +- link nbclassic docs, note Lab 4 drop notebook dependency [#13830](https://github.com/jupyterlab/jupyterlab/pull/13830) ([@RRosio](https://github.com/RRosio)) +- Improve form renderer registry [#13823](https://github.com/jupyterlab/jupyterlab/pull/13823) ([@fcollonval](https://github.com/fcollonval)) +- Bump ruff from 0.0.177 to 0.0.226 [#13819](https://github.com/jupyterlab/jupyterlab/pull/13819) ([@dependabot](https://github.com/dependabot)) +- Bug fixes/revisions for the Lab extension tutorial [#13813](https://github.com/jupyterlab/jupyterlab/pull/13813) ([@fcollonval](https://github.com/fcollonval)) +- Updates jupyter_ydoc, removes the docprovider and uses drives as providers [#13786](https://github.com/jupyterlab/jupyterlab/pull/13786) ([@hbcarlos](https://github.com/hbcarlos)) +- Merge Component registries [#13769](https://github.com/jupyterlab/jupyterlab/pull/13769) ([@brichet](https://github.com/brichet)) +- Remove deprecated `window.jupyterlab` [#13767](https://github.com/jupyterlab/jupyterlab/pull/13767) ([@jtpio](https://github.com/jtpio)) +- Minor improvements to update the tutorial [#13766](https://github.com/jupyterlab/jupyterlab/pull/13766) ([@fcollonval](https://github.com/fcollonval)) +- Fix typo in release instructions [#13754](https://github.com/jupyterlab/jupyterlab/pull/13754) ([@jasongrout](https://github.com/jasongrout)) +- Upgrades Python to 3.10, Node to 18 [#13722](https://github.com/jupyterlab/jupyterlab/pull/13722) ([@JasonWeill](https://github.com/JasonWeill)) +- Update notebook.rst [#13717](https://github.com/jupyterlab/jupyterlab/pull/13717) ([@gabalafou](https://github.com/gabalafou)) +- Fix links in `CHANGELOG.md` [#13698](https://github.com/jupyterlab/jupyterlab/pull/13698) ([@jtpio](https://github.com/jtpio)) +- update demo binder link to latest master [#13697](https://github.com/jupyterlab/jupyterlab/pull/13697) ([@akhmerov](https://github.com/akhmerov)) +- Update API documentation links [#13695](https://github.com/jupyterlab/jupyterlab/pull/13695) ([@hsuanxyz](https://github.com/hsuanxyz)) +- Update plugin ID of hub extension [#13688](https://github.com/jupyterlab/jupyterlab/pull/13688) ([@mctoohey](https://github.com/mctoohey)) +- Upgrades Xterm to v. 5 [#13685](https://github.com/jupyterlab/jupyterlab/pull/13685) ([@JasonWeill](https://github.com/JasonWeill)) +- Improve completer rendering performance [#13663](https://github.com/jupyterlab/jupyterlab/pull/13663) ([@krassowski](https://github.com/krassowski)) +- Use tokens to extend CodeMirror editors [#13639](https://github.com/jupyterlab/jupyterlab/pull/13639) ([@fcollonval](https://github.com/fcollonval)) +- Add the `scaleFactor` value from the embed options when creating the PNG representation for a Vega-based chart [#13610](https://github.com/jupyterlab/jupyterlab/pull/13610) ([@joaopalmeiro](https://github.com/joaopalmeiro)) +- Bump react 18 [#13607](https://github.com/jupyterlab/jupyterlab/pull/13607) ([@brichet](https://github.com/brichet)) +- Copy edit for privacy policy docs [#13594](https://github.com/jupyterlab/jupyterlab/pull/13594) ([@JasonWeill](https://github.com/JasonWeill)) +- Remove old editor user caret widget (dead code) and selection style [#13586](https://github.com/jupyterlab/jupyterlab/pull/13586) ([@fcollonval](https://github.com/fcollonval)) +- Drop typestyle [#13584](https://github.com/jupyterlab/jupyterlab/pull/13584) ([@fcollonval](https://github.com/fcollonval)) +- Documentation RTC and user service [#13578](https://github.com/jupyterlab/jupyterlab/pull/13578) ([@hbcarlos](https://github.com/hbcarlos)) +- Adopt ruff and clean up pre-commit [#13562](https://github.com/jupyterlab/jupyterlab/pull/13562) ([@blink1073](https://github.com/blink1073)) +- Sanitize notification message [#13510](https://github.com/jupyterlab/jupyterlab/pull/13510) ([@fcollonval](https://github.com/fcollonval)) +- Follow-on to events service [#13485](https://github.com/jupyterlab/jupyterlab/pull/13485) ([@afshin](https://github.com/afshin)) +- Drop the `moment` dependency [#13469](https://github.com/jupyterlab/jupyterlab/pull/13469) ([@jtpio](https://github.com/jtpio)) +- Remove broken URL [#13445](https://github.com/jupyterlab/jupyterlab/pull/13445) ([@fcollonval](https://github.com/fcollonval)) +- Use default URL in test mock-up [#13443](https://github.com/jupyterlab/jupyterlab/pull/13443) ([@fcollonval](https://github.com/fcollonval)) +- Allows to pause the execution during debug [#13433](https://github.com/jupyterlab/jupyterlab/pull/13433) ([@brichet](https://github.com/brichet)) +- Update the tutorial to reflect the changes in the latest cookiecutterâ€Ļ [#13417](https://github.com/jupyterlab/jupyterlab/pull/13417) ([@frivas-at-navteca](https://github.com/frivas-at-navteca)) +- Move configuration to jupyter-server-ydoc [#13413](https://github.com/jupyterlab/jupyterlab/pull/13413) ([@davidbrochart](https://github.com/davidbrochart)) +- Suggest adding video preview in PR template [#13410](https://github.com/jupyterlab/jupyterlab/pull/13410) ([@andrii-i](https://github.com/andrii-i)) +- Add announcements [#13365](https://github.com/jupyterlab/jupyterlab/pull/13365) ([@fcollonval](https://github.com/fcollonval)) +- Fix Binder for jupyter-server v2 [#13344](https://github.com/jupyterlab/jupyterlab/pull/13344) ([@fcollonval](https://github.com/fcollonval)) +- Add mdformat plugins [#13335](https://github.com/jupyterlab/jupyterlab/pull/13335) ([@blink1073](https://github.com/blink1073)) +- Remove duplicate changelog marker [#13325](https://github.com/jupyterlab/jupyterlab/pull/13325) ([@jtpio](https://github.com/jtpio)) +- Switch to releaser v2 [#13322](https://github.com/jupyterlab/jupyterlab/pull/13322) ([@blink1073](https://github.com/blink1073)) +- Backport 3.5.0 changelog on master [#13318](https://github.com/jupyterlab/jupyterlab/pull/13318) ([@fcollonval](https://github.com/fcollonval)) +- Scroll to cell by ID based on hash fragment [#13285](https://github.com/jupyterlab/jupyterlab/pull/13285) ([@krassowski](https://github.com/krassowski)) +- Correct starting docs: working directory path sample code [#13261](https://github.com/jupyterlab/jupyterlab/pull/13261) ([@hugetim](https://github.com/hugetim)) +- Update README.md [#13257](https://github.com/jupyterlab/jupyterlab/pull/13257) ([@liliyao2022](https://github.com/liliyao2022)) +- Improve documentation [#13232](https://github.com/jupyterlab/jupyterlab/pull/13232) ([@fcollonval](https://github.com/fcollonval)) +- Update example documentation: `lab -> app` [#13223](https://github.com/jupyterlab/jupyterlab/pull/13223) ([@davidbrochart](https://github.com/davidbrochart)) +- Relax doc provider API [#13214](https://github.com/jupyterlab/jupyterlab/pull/13214) ([@fcollonval](https://github.com/fcollonval)) +- Remove unused modelDBFactory [#13213](https://github.com/jupyterlab/jupyterlab/pull/13213) ([@fcollonval](https://github.com/fcollonval)) +- Update docs to `jupyter_server_config.py` [#13208](https://github.com/jupyterlab/jupyterlab/pull/13208) ([@jtpio](https://github.com/jtpio)) +- Fix removing out of view cells [#13194](https://github.com/jupyterlab/jupyterlab/pull/13194) ([@fcollonval](https://github.com/fcollonval)) +- Fix broken links in RELEASE.md file [#13193](https://github.com/jupyterlab/jupyterlab/pull/13193) ([@brichet](https://github.com/brichet)) +- Drop node-fetch for galata helpers [#13029](https://github.com/jupyterlab/jupyterlab/pull/13029) ([@fcollonval](https://github.com/fcollonval)) +- Fix lumino API documentation links [#13021](https://github.com/jupyterlab/jupyterlab/pull/13021) ([@fcollonval](https://github.com/fcollonval)) +- Support stateStorage for API calls [#13015](https://github.com/jupyterlab/jupyterlab/pull/13015) ([@fcollonval](https://github.com/fcollonval)) +- Fix customize expected reference [#13009](https://github.com/jupyterlab/jupyterlab/pull/13009) ([@fcollonval](https://github.com/fcollonval)) +- Update to Lumino 2 [#12992](https://github.com/jupyterlab/jupyterlab/pull/12992) ([@afshin](https://github.com/afshin)) +- Force using nbconvert v7 or higher for documentation [#12990](https://github.com/jupyterlab/jupyterlab/pull/12990) ([@fcollonval](https://github.com/fcollonval)) +- Update to TypeScript 4.7 in the migration guide [#12985](https://github.com/jupyterlab/jupyterlab/pull/12985) ([@jtpio](https://github.com/jtpio)) +- Add notification queue and display using toast [#12959](https://github.com/jupyterlab/jupyterlab/pull/12959) ([@telamonian](https://github.com/telamonian)) +- Prompt for renaming at first manual save [#12953](https://github.com/jupyterlab/jupyterlab/pull/12953) ([@fcollonval](https://github.com/fcollonval)) +- LSP follow-up [#12899](https://github.com/jupyterlab/jupyterlab/pull/12899) ([@trungleduc](https://github.com/trungleduc)) +- Split commands in two blocks in the contributing guide [#12898](https://github.com/jupyterlab/jupyterlab/pull/12898) ([@jtpio](https://github.com/jtpio)) +- Document building JupyterLab on osx-arm64 platforms [#12882](https://github.com/jupyterlab/jupyterlab/pull/12882) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- Add alt text to documentation [#12879](https://github.com/jupyterlab/jupyterlab/pull/12879) ([@isabela-pf](https://github.com/isabela-pf)) +- Remove reference to unmaintained nb_conda_kernels [#12878](https://github.com/jupyterlab/jupyterlab/pull/12878) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- Add license header fix job [#12872](https://github.com/jupyterlab/jupyterlab/pull/12872) ([@fcollonval](https://github.com/fcollonval)) +- New extension manager [#12866](https://github.com/jupyterlab/jupyterlab/pull/12866) ([@fcollonval](https://github.com/fcollonval)) +- Run kernel on cell execution when no kernel [#12858](https://github.com/jupyterlab/jupyterlab/pull/12858) ([@a3626a](https://github.com/a3626a)) +- Don't suggest deprecated command [#12855](https://github.com/jupyterlab/jupyterlab/pull/12855) ([@ryanlovett](https://github.com/ryanlovett)) +- Store Y updates [#12852](https://github.com/jupyterlab/jupyterlab/pull/12852) ([@davidbrochart](https://github.com/davidbrochart)) +- Fixes renaming files from title while using a custom drive [#12849](https://github.com/jupyterlab/jupyterlab/pull/12849) ([@hbcarlos](https://github.com/hbcarlos)) +- Removes info about meeting notes on Binder [#12847](https://github.com/jupyterlab/jupyterlab/pull/12847) ([@JasonWeill](https://github.com/JasonWeill)) +- Adds version maintenance policy [#12829](https://github.com/jupyterlab/jupyterlab/pull/12829) ([@JasonWeill](https://github.com/JasonWeill)) +- #12717 Add a new section: automation of local dev environments [#12806](https://github.com/jupyterlab/jupyterlab/pull/12806) ([@markgreene74](https://github.com/markgreene74)) +- Use Vega SVG renderer to drop canvas dependency [#12785](https://github.com/jupyterlab/jupyterlab/pull/12785) ([@fcollonval](https://github.com/fcollonval)) +- Removes lighthouse and markdown-loader-jest [#12776](https://github.com/jupyterlab/jupyterlab/pull/12776) ([@fcollonval](https://github.com/fcollonval)) +- Explicitly set language to `en` in `conf.py` [#12707](https://github.com/jupyterlab/jupyterlab/pull/12707) ([@jtpio](https://github.com/jtpio)) +- Split the Document Manager extension into multiple plugins [#12701](https://github.com/jupyterlab/jupyterlab/pull/12701) ([@jtpio](https://github.com/jtpio)) +- Add more explanation for internationalization (translation python package) [#12635](https://github.com/jupyterlab/jupyterlab/pull/12635) ([@a3626a](https://github.com/a3626a)) +- Fix failing check links [#12627](https://github.com/jupyterlab/jupyterlab/pull/12627) ([@jtpio](https://github.com/jtpio)) +- Update README wording [#12610](https://github.com/jupyterlab/jupyterlab/pull/12610) ([@fcollonval](https://github.com/fcollonval)) -- Skip checking for updates in UI tests [#14609](https://github.com/jupyterlab/jupyterlab/pull/14609) ([@fcollonval](https://github.com/fcollonval)) -- Fix CI: remove/update broken docs links [#14414](https://github.com/jupyterlab/jupyterlab/pull/14414) ([@krassowski](https://github.com/krassowski)) -- Fix documentation build on CI [#14423](https://github.com/jupyterlab/jupyterlab/pull/14423) ([@jtpio](https://github.com/jtpio)) +#### API and Breaking Changes -### Documentation improvements +- Harmonizes form renderer ids [#14415](https://github.com/jupyterlab/jupyterlab/pull/14415) ([@brichet](https://github.com/brichet)) +- Remove deprecated code [#14160](https://github.com/jupyterlab/jupyterlab/pull/14160) ([@fcollonval](https://github.com/fcollonval)) +- Move the file name searcher to the file browser toolbar [#14064](https://github.com/jupyterlab/jupyterlab/pull/14064) ([@jtpio](https://github.com/jtpio)) +- Using metadataform for default notebooktools [#14026](https://github.com/jupyterlab/jupyterlab/pull/14026) ([@brichet](https://github.com/brichet)) +- Remove vdom packages [#13949](https://github.com/jupyterlab/jupyterlab/pull/13949) ([@fcollonval](https://github.com/fcollonval)) +- Fix LSP adapter errors on tab close [#13918](https://github.com/jupyterlab/jupyterlab/pull/13918) ([@afshin](https://github.com/afshin)) +- Switch to VEGALITE5_MIME_TYPE [#13893](https://github.com/jupyterlab/jupyterlab/pull/13893) ([@ChristopherDavisUCI](https://github.com/ChristopherDavisUCI)) +- upgrade to MathJax 3 \[with git history\] [#13877](https://github.com/jupyterlab/jupyterlab/pull/13877) ([@dlqqq](https://github.com/dlqqq)) +- Improve form renderer registry [#13823](https://github.com/jupyterlab/jupyterlab/pull/13823) ([@fcollonval](https://github.com/fcollonval)) +- Reduces the context of the form used in metadataform [#13781](https://github.com/jupyterlab/jupyterlab/pull/13781) ([@brichet](https://github.com/brichet)) +- Merge Component registries [#13769](https://github.com/jupyterlab/jupyterlab/pull/13769) ([@brichet](https://github.com/brichet)) +- Remove deprecated `window.jupyterlab` [#13767](https://github.com/jupyterlab/jupyterlab/pull/13767) ([@jtpio](https://github.com/jtpio)) +- Upgrades Python to 3.10, Node to 18 [#13722](https://github.com/jupyterlab/jupyterlab/pull/13722) ([@JasonWeill](https://github.com/JasonWeill)) +- Remove not needed `Completer.IRenderer.sanitizer` [#13700](https://github.com/jupyterlab/jupyterlab/pull/13700) ([@fcollonval](https://github.com/fcollonval)) +- Remove old completer API [#13615](https://github.com/jupyterlab/jupyterlab/pull/13615) ([@krassowski](https://github.com/krassowski)) +- Remove old editor user caret widget (dead code) and selection style [#13586](https://github.com/jupyterlab/jupyterlab/pull/13586) ([@fcollonval](https://github.com/fcollonval)) +- Drop the `moment` dependency [#13469](https://github.com/jupyterlab/jupyterlab/pull/13469) ([@jtpio](https://github.com/jtpio)) +- Move the toggle file browser logic to the widget [#13466](https://github.com/jupyterlab/jupyterlab/pull/13466) ([@brichet](https://github.com/brichet)) +- enable document model specific collaboration [#13458](https://github.com/jupyterlab/jupyterlab/pull/13458) ([@dlqqq](https://github.com/dlqqq)) +- Extract @jupyterlab/shared-models to @jupyter-notebook/ydoc [#13389](https://github.com/jupyterlab/jupyterlab/pull/13389) ([@fcollonval](https://github.com/fcollonval)) +- Store document info in the state not in a separate context map out of the document interface. [#13317](https://github.com/jupyterlab/jupyterlab/pull/13317) ([@fcollonval](https://github.com/fcollonval)) +- Drop modelDB from code editor [#13247](https://github.com/jupyterlab/jupyterlab/pull/13247) ([@fcollonval](https://github.com/fcollonval)) +- Use file ID [#13246](https://github.com/jupyterlab/jupyterlab/pull/13246) ([@davidbrochart](https://github.com/davidbrochart)) +- Relax doc provider API [#13214](https://github.com/jupyterlab/jupyterlab/pull/13214) ([@fcollonval](https://github.com/fcollonval)) +- Remove unused modelDBFactory [#13213](https://github.com/jupyterlab/jupyterlab/pull/13213) ([@fcollonval](https://github.com/fcollonval)) +- Improve shared-models API [#13168](https://github.com/jupyterlab/jupyterlab/pull/13168) ([@fcollonval](https://github.com/fcollonval)) +- Drop node-fetch for galata helpers [#13029](https://github.com/jupyterlab/jupyterlab/pull/13029) ([@fcollonval](https://github.com/fcollonval)) +- New extension manager [#12866](https://github.com/jupyterlab/jupyterlab/pull/12866) ([@fcollonval](https://github.com/fcollonval)) +- Fixes renaming files from title while using a custom drive [#12849](https://github.com/jupyterlab/jupyterlab/pull/12849) ([@hbcarlos](https://github.com/hbcarlos)) +- Split the Document Manager extension into multiple plugins [#12701](https://github.com/jupyterlab/jupyterlab/pull/12701) ([@jtpio](https://github.com/jtpio)) +- Add events service [#12667](https://github.com/jupyterlab/jupyterlab/pull/12667) ([@afshin](https://github.com/afshin)) -- Fix broken links in galata/README.md [#14451](https://github.com/jupyterlab/jupyterlab/pull/14451) ([@gabalafou](https://github.com/gabalafou)) -- Fix documentation build on CI [#14423](https://github.com/jupyterlab/jupyterlab/pull/14423) ([@jtpio](https://github.com/jtpio)) -- Backport on branch 3.6.x (Updates announcements to better conform to RFC atom standard. (#14480)) [#14499](https://github.com/jupyterlab/jupyterlab/pull/14499) ([@fcollonval](https://github.com/fcollonval)) +#### Contributors to this release -### Contributors to this release +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-07-13&to=2023-04-27&type=c)) -([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2023-03-31&to=2023-05-31&type=c)) +[@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-07-13..2023-04-27&type=Issues) | [@a3626a](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aa3626a+updated%3A2021-07-13..2023-04-27&type=Issues) | [@aditya211935](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aaditya211935+updated%3A2021-07-13..2023-04-27&type=Issues) | [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-07-13..2023-04-27&type=Issues) | [@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2021-07-13..2023-04-27&type=Issues) | [@ajbozarth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aajbozarth+updated%3A2021-07-13..2023-04-27&type=Issues) | [@akhmerov](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aakhmerov+updated%3A2021-07-13..2023-04-27&type=Issues) | [@alec-kr](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aalec-kr+updated%3A2021-07-13..2023-04-27&type=Issues) | [@Alexboiboi](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AAlexboiboi+updated%3A2021-07-13..2023-04-27&type=Issues) | [@andrii-i](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrii-i+updated%3A2021-07-13..2023-04-27&type=Issues) | [@athornton](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aathornton+updated%3A2021-07-13..2023-04-27&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-07-13..2023-04-27&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-07-13..2023-04-27&type=Issues) | [@brichet](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abrichet+updated%3A2021-07-13..2023-04-27&type=Issues) | [@c00kie123](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ac00kie123+updated%3A2021-07-13..2023-04-27&type=Issues) | [@cccs-nik](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Acccs-nik+updated%3A2021-07-13..2023-04-27&type=Issues) | [@chbrandt](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Achbrandt+updated%3A2021-07-13..2023-04-27&type=Issues) | [@ChristopherDavisUCI](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AChristopherDavisUCI+updated%3A2021-07-13..2023-04-27&type=Issues) | [@damiend97](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adamiend97+updated%3A2021-07-13..2023-04-27&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-07-13..2023-04-27&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2021-07-13..2023-04-27&type=Issues) | [@dlqqq](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adlqqq+updated%3A2021-07-13..2023-04-27&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-07-13..2023-04-27&type=Issues) | [@kamalika0363](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akamalika0363+updated%3A2021-07-13..2023-04-27&type=Issues) | [@domoritz](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adomoritz+updated%3A2021-07-13..2023-04-27&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-07-13..2023-04-27&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-07-13..2023-04-27&type=Issues) | [@ericsnekbytes](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aericsnekbytes+updated%3A2021-07-13..2023-04-27&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-07-13..2023-04-27&type=Issues) | [@firai](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afirai+updated%3A2021-07-13..2023-04-27&type=Issues) | [@FoSuCloud](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AFoSuCloud+updated%3A2021-07-13..2023-04-27&type=Issues) | [@fperez](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afperez+updated%3A2021-07-13..2023-04-27&type=Issues) | [@frenzymadness](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afrenzymadness+updated%3A2021-07-13..2023-04-27&type=Issues) | [@frivas-at-navteca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afrivas-at-navteca+updated%3A2021-07-13..2023-04-27&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2021-07-13..2023-04-27&type=Issues) | [@GabrielaVives](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AGabrielaVives+updated%3A2021-07-13..2023-04-27&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-07-13..2023-04-27&type=Issues) | [@HaudinFlorence](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AHaudinFlorence+updated%3A2021-07-13..2023-04-27&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-07-13..2023-04-27&type=Issues) | [@hsuanxyz](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahsuanxyz+updated%3A2021-07-13..2023-04-27&type=Issues) | [@hugetim](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahugetim+updated%3A2021-07-13..2023-04-27&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-07-13..2023-04-27&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-07-13..2023-04-27&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2021-07-13..2023-04-27&type=Issues) | [@jmk89](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajmk89+updated%3A2021-07-13..2023-04-27&type=Issues) | [@joaopalmeiro](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajoaopalmeiro+updated%3A2021-07-13..2023-04-27&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2021-07-13..2023-04-27&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-07-13..2023-04-27&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-07-13..2023-04-27&type=Issues) | [@kenyaachon](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akenyaachon+updated%3A2021-07-13..2023-04-27&type=Issues) | [@kostyafarber](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akostyafarber+updated%3A2021-07-13..2023-04-27&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-07-13..2023-04-27&type=Issues) | [@kulsoomzahra](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akulsoomzahra+updated%3A2021-07-13..2023-04-27&type=Issues) | [@liliyao2022](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aliliyao2022+updated%3A2021-07-13..2023-04-27&type=Issues) | [@malemburg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amalemburg+updated%3A2021-07-13..2023-04-27&type=Issues) | [@markgreene74](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarkgreene74+updated%3A2021-07-13..2023-04-27&type=Issues) | [@marthacryan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarthacryan+updated%3A2021-07-13..2023-04-27&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2021-07-13..2023-04-27&type=Issues) | [@matthewturk](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amatthewturk+updated%3A2021-07-13..2023-04-27&type=Issues) | [@mctoohey](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amctoohey+updated%3A2021-07-13..2023-04-27&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-07-13..2023-04-27&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-07-13..2023-04-27&type=Issues) | [@mgcth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amgcth+updated%3A2021-07-13..2023-04-27&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aminrk+updated%3A2021-07-13..2023-04-27&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2021-07-13..2023-04-27&type=Issues) | [@NikolayXHD](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ANikolayXHD+updated%3A2021-07-13..2023-04-27&type=Issues) | [@oscar6echo](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aoscar6echo+updated%3A2021-07-13..2023-04-27&type=Issues) | [@peytondmurray](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apeytondmurray+updated%3A2021-07-13..2023-04-27&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apre-commit-ci+updated%3A2021-07-13..2023-04-27&type=Issues) | [@psychemedia](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apsychemedia+updated%3A2021-07-13..2023-04-27&type=Issues) | [@RobbyPratl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ARobbyPratl+updated%3A2021-07-13..2023-04-27&type=Issues) | [@RRosio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ARRosio+updated%3A2021-07-13..2023-04-27&type=Issues) | [@rursprung](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Arursprung+updated%3A2021-07-13..2023-04-27&type=Issues) | [@siddartha-10](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asiddartha-10+updated%3A2021-07-13..2023-04-27&type=Issues) | [@steff456](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asteff456+updated%3A2021-07-13..2023-04-27&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-07-13..2023-04-27&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2021-07-13..2023-04-27&type=Issues) | [@thetorpedodog](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Athetorpedodog+updated%3A2021-07-13..2023-04-27&type=Issues) | [@thomasaarholt](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Athomasaarholt+updated%3A2021-07-13..2023-04-27&type=Issues) | [@tonyfast](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atonyfast+updated%3A2021-07-13..2023-04-27&type=Issues) | [@trallard](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrallard+updated%3A2021-07-13..2023-04-27&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-07-13..2023-04-27&type=Issues) | [@vidartf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avidartf+updated%3A2021-07-13..2023-04-27&type=Issues) | [@vthinkxie](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avthinkxie+updated%3A2021-07-13..2023-04-27&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-07-13..2023-04-27&type=Issues) | [@yangql176](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayangql176+updated%3A2021-07-13..2023-04-27&type=Issues) | [@yanmulin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayanmulin+updated%3A2021-07-13..2023-04-27&type=Issues) | [@yczhangsjtu](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayczhangsjtu+updated%3A2021-07-13..2023-04-27&type=Issues) | [@yumyumqing](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayumyumqing+updated%3A2021-07-13..2023-04-27&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2021-07-13..2023-04-27&type=Issues) | [@zrottman](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Azrottman+updated%3A2021-07-13..2023-04-27&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AZsailer+updated%3A2021-07-13..2023-04-27&type=Issues) -[@andrii-i](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrii-i+updated%3A2023-03-31..2023-05-31&type=Issues) | [@brichet](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abrichet+updated%3A2023-03-31..2023-05-31&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2023-03-31..2023-05-31&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2023-03-31..2023-05-31&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2023-03-31..2023-05-31&type=Issues) | [@GabrielaVives](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AGabrielaVives+updated%3A2023-03-31..2023-05-31&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2023-03-31..2023-05-31&type=Issues) | [@HaudinFlorence](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AHaudinFlorence+updated%3A2023-03-31..2023-05-31&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2023-03-31..2023-05-31&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2023-03-31..2023-05-31&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2023-03-31..2023-05-31&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2023-03-31..2023-05-31&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2023-03-31..2023-05-31&type=Issues) | [@lumberbot-app](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Alumberbot-app+updated%3A2023-03-31..2023-05-31&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2023-03-31..2023-05-31&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2023-03-31..2023-05-31&type=Issues) | [@tonyfast](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atonyfast+updated%3A2023-03-31..2023-05-31&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2023-03-31..2023-05-31&type=Issues) +## v3.6 -## 3.6.3 +### 3.6.3 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.6.2...639a54c6b8ae9e8375f952d38539a233447aca73)) -### Maintenance and upkeep improvements +#### Maintenance and upkeep improvements - Bump lumino 1.x [#14286](https://github.com/jupyterlab/jupyterlab/pull/14286) ([@fcollonval](https://github.com/fcollonval)) - Provide @jupyterlab/shared-models as singleton [#14229](https://github.com/jupyterlab/jupyterlab/pull/14229) ([@fcollonval](https://github.com/fcollonval)) -### Documentation improvements +#### Documentation improvements - Provide @jupyterlab/shared-models as singleton [#14229](https://github.com/jupyterlab/jupyterlab/pull/14229) ([@fcollonval](https://github.com/fcollonval)) -### Contributors to this release +#### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2023-03-20&to=2023-03-30&type=c)) [@andrii-i](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrii-i+updated%3A2023-03-20..2023-03-30&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2023-03-20..2023-03-30&type=Issues) | [@brichet](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abrichet+updated%3A2023-03-20..2023-03-30&type=Issues) | [@damiend97](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adamiend97+updated%3A2023-03-20..2023-03-30&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2023-03-20..2023-03-30&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2023-03-20..2023-03-30&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2023-03-20..2023-03-30&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2023-03-20..2023-03-30&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2023-03-20..2023-03-30&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2023-03-20..2023-03-30&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2023-03-20..2023-03-30&type=Issues) -## 3.6.2 +### 3.6.2 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.6.1...faeab2c33cf857bef14b9e26ff9ec22cf82aa9b1)) -### Bugs fixed +#### Bugs fixed - Fix save as without changing the file name [#14212](https://github.com/jupyterlab/jupyterlab/pull/14212) ([@hbcarlos](https://github.com/hbcarlos)) - Fix save as in collaborative mode [#14182](https://github.com/jupyterlab/jupyterlab/pull/14182) ([@hbcarlos](https://github.com/hbcarlos)) @@ -128,37 +1342,37 @@ - Use local paths instead of driveName:path in the shared model [#13866](https://github.com/jupyterlab/jupyterlab/pull/13866) ([@hbcarlos](https://github.com/hbcarlos)) - use singleton boolean type for codemirror `lineWiseCopyCut` setting [#14055](https://github.com/jupyterlab/jupyterlab/pull/14055) ([@bollwyvl](https://github.com/bollwyvl)) -### Maintenance and upkeep improvements +#### Maintenance and upkeep improvements - Fix integrity [#14226](https://github.com/jupyterlab/jupyterlab/pull/14226) ([@fcollonval](https://github.com/fcollonval)) - Increases timeout [#14045](https://github.com/jupyterlab/jupyterlab/pull/14045) ([@brichet](https://github.com/brichet)) - Use Python 3.11 for js-debugger tests [#13941](https://github.com/jupyterlab/jupyterlab/pull/13941) ([@fcollonval](https://github.com/fcollonval)) - Fix verdaccio start up with nodejs 18.14.0 [#13959](https://github.com/jupyterlab/jupyterlab/pull/13959) ([@fcollonval](https://github.com/fcollonval)) -### Documentation improvements +#### Documentation improvements - Add note for jest configuration and JLab 3.6 [#14207](https://github.com/jupyterlab/jupyterlab/pull/14207) ([@fcollonval](https://github.com/fcollonval)) -### Contributors to this release +#### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2023-02-03&to=2023-03-20&type=c)) [@andrii-i](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrii-i+updated%3A2023-02-03..2023-03-20&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2023-02-03..2023-03-20&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2023-02-03..2023-03-20&type=Issues) | [@brichet](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abrichet+updated%3A2023-02-03..2023-03-20&type=Issues) | [@bt-](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abt-+updated%3A2023-02-03..2023-03-20&type=Issues) | [@dlqqq](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adlqqq+updated%3A2023-02-03..2023-03-20&type=Issues) | [@domoritz](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adomoritz+updated%3A2023-02-03..2023-03-20&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2023-02-03..2023-03-20&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2023-02-03..2023-03-20&type=Issues) | [@fperez](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afperez+updated%3A2023-02-03..2023-03-20&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2023-02-03..2023-03-20&type=Issues) | [@GabrielaVives](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AGabrielaVives+updated%3A2023-02-03..2023-03-20&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2023-02-03..2023-03-20&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2023-02-03..2023-03-20&type=Issues) | [@HaudinFlorence](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AHaudinFlorence+updated%3A2023-02-03..2023-03-20&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2023-02-03..2023-03-20&type=Issues) | [@ianhi](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aianhi+updated%3A2023-02-03..2023-03-20&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2023-02-03..2023-03-20&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2023-02-03..2023-03-20&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2023-02-03..2023-03-20&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2023-02-03..2023-03-20&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2023-02-03..2023-03-20&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2023-02-03..2023-03-20&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2023-02-03..2023-03-20&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2023-02-03..2023-03-20&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2023-02-03..2023-03-20&type=Issues) | [@psychemedia](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apsychemedia+updated%3A2023-02-03..2023-03-20&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2023-02-03..2023-03-20&type=Issues) | [@tonyfast](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atonyfast+updated%3A2023-02-03..2023-03-20&type=Issues) | [@vidartf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avidartf+updated%3A2023-02-03..2023-03-20&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2023-02-03..2023-03-20&type=Issues) -## 3.6.1 +### 3.6.1 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.6.0...ef12e4b9e7874489bb6bf6cda91dd08697f2b3c9)) -### Bugs fixed +#### Bugs fixed - Revert target to ES2017 [#13914](https://github.com/jupyterlab/jupyterlab/pull/13914) ([@fcollonval](https://github.com/fcollonval)) -### Documentation improvements +#### Documentation improvements - Revert target to ES2017 [#13914](https://github.com/jupyterlab/jupyterlab/pull/13914) ([@fcollonval](https://github.com/fcollonval)) - Fix minor typo in urls.rst [#13902](https://github.com/jupyterlab/jupyterlab/pull/13902) ([@chbrandt](https://github.com/chbrandt)) -### Contributors to this release +#### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2023-02-02&to=2023-02-03&type=c)) @@ -321,84 +1535,11 @@ ## v3.5 -### 3.5.3 - -([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.5.2...38557b9cc49aca310264476c9c9d9f003891dcb2)) - -#### Bugs fixed - -- Fix `preferred_dir` for examples [#13788](https://github.com/jupyterlab/jupyterlab/pull/13788) ([@fcollonval](https://github.com/fcollonval)) -- Bump canvas to version with nodejs 18 binaries [#13783](https://github.com/jupyterlab/jupyterlab/pull/13783) ([@fcollonval](https://github.com/fcollonval)) -- Fix handling of `settingEditorType` [#13761](https://github.com/jupyterlab/jupyterlab/pull/13761) ([@jtpio](https://github.com/jtpio)) -- Write the browser open files for test [#13634](https://github.com/jupyterlab/jupyterlab/pull/13634) ([@fcollonval](https://github.com/fcollonval)) - -#### Maintenance and upkeep improvements - -- Clean examples [#13812](https://github.com/jupyterlab/jupyterlab/pull/13812) ([@fcollonval](https://github.com/fcollonval)) -- Fix `preferred_dir` for examples [#13788](https://github.com/jupyterlab/jupyterlab/pull/13788) ([@fcollonval](https://github.com/fcollonval)) -- Bump canvas to version with nodejs 18 binaries [#13783](https://github.com/jupyterlab/jupyterlab/pull/13783) ([@fcollonval](https://github.com/fcollonval)) -- Drop the dependency on `@jupyterlab/buildutils` in `@jupyterlab/builder` [#13741](https://github.com/jupyterlab/jupyterlab/pull/13741) ([@jtpio](https://github.com/jtpio)) -- Write the browser open files for test [#13634](https://github.com/jupyterlab/jupyterlab/pull/13634) ([@fcollonval](https://github.com/fcollonval)) - -#### Documentation improvements - -- Force jupyter-server v1 to check against notebook v6 [#13716](https://github.com/jupyterlab/jupyterlab/pull/13716) ([@fcollonval](https://github.com/fcollonval)) - -#### Other merged PRs - -#### Contributors to this release - -([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-12-19&to=2023-01-23&type=c)) - -[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-12-19..2023-01-23&type=Issues) | [@andrii-i](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrii-i+updated%3A2022-12-19..2023-01-23&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-12-19..2023-01-23&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-12-19..2023-01-23&type=Issues) | [@brichet](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abrichet+updated%3A2022-12-19..2023-01-23&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-12-19..2023-01-23&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-12-19..2023-01-23&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-12-19..2023-01-23&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-12-19..2023-01-23&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-12-19..2023-01-23&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-12-19..2023-01-23&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-12-19..2023-01-23&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-12-19..2023-01-23&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-12-19..2023-01-23&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-12-19..2023-01-23&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2022-12-19..2023-01-23&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-12-19..2023-01-23&type=Issues) - -### 3.5.2 - -([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.5.1...d309941e9019ada44d1124956dff9a3ec1a54c48)) - -#### Bugs fixed - -- use jupyter_config_dir instead of config_path\[0\] for workspaces, settings [#13589](https://github.com/jupyterlab/jupyterlab/pull/13589) ([@minrk](https://github.com/minrk)) - -#### Maintenance and upkeep improvements - -- Fix Python test dependencies [#13508](https://github.com/jupyterlab/jupyterlab/pull/13508) ([@fcollonval](https://github.com/fcollonval)) - -#### Contributors to this release - -([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-12-05&to=2022-12-19&type=c)) - -[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-12-05..2022-12-19&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-12-05..2022-12-19&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-12-05..2022-12-19&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-12-05..2022-12-19&type=Issues) | [@HaudinFlorence](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AHaudinFlorence+updated%3A2022-12-05..2022-12-19&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-12-05..2022-12-19&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-12-05..2022-12-19&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-12-05..2022-12-19&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-12-05..2022-12-19&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-12-05..2022-12-19&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-12-05..2022-12-19&type=Issues) | [@vidartf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avidartf+updated%3A2022-12-05..2022-12-19&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-12-05..2022-12-19&type=Issues) - -### 3.5.1 - -([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.5.0...eaa0d1e106097b05da27f305227e5e5007723e61)) - -#### Bugs fixed - -- Fixes sharing metadata [#13491](https://github.com/jupyterlab/jupyterlab/pull/13491) ([@hbcarlos](https://github.com/hbcarlos)) - -#### Maintenance and upkeep improvements - -- Bump sanitize-html to 2.7.3 [#13509](https://github.com/jupyterlab/jupyterlab/pull/13509) ([@fcollonval](https://github.com/fcollonval)) -- Switch to releaser v2 [#13327](https://github.com/jupyterlab/jupyterlab/pull/13327) ([@blink1073](https://github.com/blink1073)) - -#### Documentation improvements - -- Update the tutorial to reflect the changes in the latest cookiecutterâ€Ļ [#13417](https://github.com/jupyterlab/jupyterlab/pull/13417) ([@frivas-at-navteca](https://github.com/frivas-at-navteca)) -- Remove changelog for pre-releases [#13312](https://github.com/jupyterlab/jupyterlab/pull/13312) ([@fcollonval](https://github.com/fcollonval)) - -#### Contributors to this release - -([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-10-24&to=2022-12-01&type=c)) - -[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-10-24..2022-12-01&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-10-24..2022-12-01&type=Issues) | [@brichet](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abrichet+updated%3A2022-10-24..2022-12-01&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-10-24..2022-12-01&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-10-24..2022-12-01&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-10-24..2022-12-01&type=Issues) | [@HaudinFlorence](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AHaudinFlorence+updated%3A2022-10-24..2022-12-01&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-10-24..2022-12-01&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-10-24..2022-12-01&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-10-24..2022-12-01&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-10-24..2022-12-01&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-10-24..2022-12-01&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-10-24..2022-12-01&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-10-24..2022-12-01&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2022-10-24..2022-12-01&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-10-24..2022-12-01&type=Issues) - -### 3.5.0 +## 3.5.0 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.8...225e7ab0844a0284bf50a567de505eb4650ec122)) -#### Enhancements made +### Enhancements made - Optimize text mimerenderer: ansi vs autolink [#13202](https://github.com/jupyterlab/jupyterlab/pull/13202) ([@vidartf](https://github.com/vidartf)) - Collapse debugger panel when disabling debugger [#13088](https://github.com/jupyterlab/jupyterlab/pull/13088) ([@yanmulin](https://github.com/yanmulin)) @@ -406,87 +1547,57 @@ - Prompt for renaming at first manual save [#12953](https://github.com/jupyterlab/jupyterlab/pull/12953) ([@fcollonval](https://github.com/fcollonval)) - Raise ceiling on `jupyter_server` dependency to \< 3 [#13068](https://github.com/jupyterlab/jupyterlab/pull/13068) ([@Zsailer](https://github.com/Zsailer)) -#### Bugs fixed +### Bugs fixed - Set `isUntitled` to false on document path changes [#13268](https://github.com/jupyterlab/jupyterlab/pull/13268) ([@fcollonval](https://github.com/fcollonval)) - Don't dispose the notebook metadata editor on active cell change [#13259](https://github.com/jupyterlab/jupyterlab/pull/13259) ([@fcollonval](https://github.com/fcollonval)) - Use keystroke format consistent with menus [#13200](https://github.com/jupyterlab/jupyterlab/pull/13200) ([@fcollonval](https://github.com/fcollonval)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Fix memory leaks [#13229](https://github.com/jupyterlab/jupyterlab/pull/13229) ([@fcollonval](https://github.com/fcollonval)) - Bump to the latest Lumino 1.x [#13190](https://github.com/jupyterlab/jupyterlab/pull/13190) ([@fcollonval](https://github.com/fcollonval)) - Update branch configuration [#13184](https://github.com/jupyterlab/jupyterlab/pull/13184) ([@fcollonval](https://github.com/fcollonval)) -#### Documentation improvements +### Documentation improvements - Update example documentation: `lab -> app` [#13223](https://github.com/jupyterlab/jupyterlab/pull/13223) ([@davidbrochart](https://github.com/davidbrochart)) - Prompt for renaming at first manual save [#12953](https://github.com/jupyterlab/jupyterlab/pull/12953) ([@fcollonval](https://github.com/fcollonval)) - Update branch configuration [#13184](https://github.com/jupyterlab/jupyterlab/pull/13184) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-10-04&to=2022-10-24&type=c)) - [@Carreau](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ACarreau+updated%3A2022-10-04..2022-10-24&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-10-04..2022-10-24&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-10-04..2022-10-24&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-10-04..2022-10-24&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-10-04..2022-10-24&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-10-04..2022-10-24&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-10-04..2022-10-24&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-10-04..2022-10-24&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-10-04..2022-10-24&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-10-04..2022-10-24&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-10-04..2022-10-24&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2022-10-04..2022-10-24&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2022-10-04..2022-10-24&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-10-04..2022-10-24&type=Issues) ## v3.4 -### 3.4.8 - -([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.7...f382949b11c54384eee8e58a0d7defe879c21718)) - -#### Enhancements made - -- Adjust CSS styles degrading performance in Chromium browsers [#13159](https://github.com/jupyterlab/jupyterlab/pull/13159) ([@krassowski](https://github.com/krassowski)) - -#### Bugs fixed - -- Always show tooltip in hover box even if edges are out of view [#13161](https://github.com/jupyterlab/jupyterlab/pull/13161) ([@krassowski](https://github.com/krassowski)) -- Fix workspace URL while cloning a workspace [#12794](https://github.com/jupyterlab/jupyterlab/pull/12794) ([@aditya211935](https://github.com/aditya211935)) -- Switch back to `display` to hide tabs [#13103](https://github.com/jupyterlab/jupyterlab/pull/13103) ([@fcollonval](https://github.com/fcollonval)) -- Preserve kernel icon aspect ratio [#13122](https://github.com/jupyterlab/jupyterlab/pull/13122) ([@fcollonval](https://github.com/fcollonval)) -- Fix cell toolbar layout [#13059](https://github.com/jupyterlab/jupyterlab/pull/13059) ([@kulsoomzahra](https://github.com/kulsoomzahra)) -- Avoid menus overflowing in small screens [#13109](https://github.com/jupyterlab/jupyterlab/pull/13109) ([@steff456](https://github.com/steff456)) - -#### Maintenance and upkeep improvements - -- Fix storybook error [#13135](https://github.com/jupyterlab/jupyterlab/pull/13135) ([@fcollonval](https://github.com/fcollonval)) -- Remove xeus-python installation for debugger test [#13113](https://github.com/jupyterlab/jupyterlab/pull/13113) ([@fcollonval](https://github.com/fcollonval)) -- Resolve core_path before calling nodejs [#13126](https://github.com/jupyterlab/jupyterlab/pull/13126) ([@fcollonval](https://github.com/fcollonval)) - -#### Contributors to this release - -([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-09-12&to=2022-10-04&type=c)) - -[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-09-12..2022-10-04&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-09-12..2022-10-04&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2022-09-12..2022-10-04&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-09-12..2022-10-04&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-09-12..2022-10-04&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-09-12..2022-10-04&type=Issues) | [@firai](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afirai+updated%3A2022-09-12..2022-10-04&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2022-09-12..2022-10-04&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-09-12..2022-10-04&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-09-12..2022-10-04&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-09-12..2022-10-04&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-09-12..2022-10-04&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-09-12..2022-10-04&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-09-12..2022-10-04&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2022-09-12..2022-10-04&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-09-12..2022-10-04&type=Issues) - -### 3.4.7 +## 3.4.7 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.6...f713e06179bb5e57fc03da5fcf49b9c8e543f684)) -#### Enhancements made +### Enhancements made - Get package name from pyproject if available [#13076](https://github.com/jupyterlab/jupyterlab/pull/13076) ([@blink1073](https://github.com/blink1073)) - Fix blurry icons in Launcher at 400% Zoom [#13065](https://github.com/jupyterlab/jupyterlab/pull/13065) ([@fcollonval](https://github.com/fcollonval)) -#### Bugs fixed +### Bugs fixed - Added mimeType for .webp image files [#13066](https://github.com/jupyterlab/jupyterlab/pull/13066) ([@alec-kr](https://github.com/alec-kr)) - Fix URL when falling back to node-fetch [#13067](https://github.com/jupyterlab/jupyterlab/pull/13067) ([@fcollonval](https://github.com/fcollonval)) - Keep completer visible when anchor is horizontally scrolled out of view [#13046](https://github.com/jupyterlab/jupyterlab/pull/13046) ([@krassowski](https://github.com/krassowski)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-09-05&to=2022-09-12&type=c)) [@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2022-09-05..2022-09-12&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-09-05..2022-09-12&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-09-05..2022-09-12&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-09-05..2022-09-12&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2022-09-05..2022-09-12&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-09-05..2022-09-12&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-09-05..2022-09-12&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-09-05..2022-09-12&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-09-05..2022-09-12&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-09-05..2022-09-12&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-09-05..2022-09-12&type=Issues) -### 3.4.6 +## 3.4.6 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.5...76459a67511b1c54df853e52d83a7fbd3badae7b)) -#### Bugs fixed +### Bugs fixed - Update Python icon to be PSF Trademark compliant [#13044](https://github.com/jupyterlab/jupyterlab/pull/13044) ([@fcollonval](https://github.com/fcollonval)) - Reorder of webpackConfig merge [#13042](https://github.com/jupyterlab/jupyterlab/pull/13042) ([@fcollonval](https://github.com/fcollonval)) @@ -496,30 +1607,30 @@ - Add scrolling to `debugger` variable renderer [#12968](https://github.com/jupyterlab/jupyterlab/pull/12968) ([@firai](https://github.com/firai)) - Fix resizing and selection of debugger variable explorer grid [#12943](https://github.com/jupyterlab/jupyterlab/pull/12943) ([@firai](https://github.com/firai)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Fix lumino API documentation links [#13021](https://github.com/jupyterlab/jupyterlab/pull/13021) ([@fcollonval](https://github.com/fcollonval)) -#### Documentation improvements +### Documentation improvements - Fix lumino API documentation links [#13021](https://github.com/jupyterlab/jupyterlab/pull/13021) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-08-10&to=2022-09-05&type=c)) [@ajbozarth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aajbozarth+updated%3A2022-08-10..2022-09-05&type=Issues) | [@athornton](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aathornton+updated%3A2022-08-10..2022-09-05&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-08-10..2022-09-05&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-08-10..2022-09-05&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-08-10..2022-09-05&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2022-08-10..2022-09-05&type=Issues) | [@ian-r-rose](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aian-r-rose+updated%3A2022-08-10..2022-09-05&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2022-08-10..2022-09-05&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-08-10..2022-09-05&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-08-10..2022-09-05&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-08-10..2022-09-05&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-08-10..2022-09-05&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2022-08-10..2022-09-05&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-08-10..2022-09-05&type=Issues) | [@KrishnaKumarHariprasannan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AKrishnaKumarHariprasannan+updated%3A2022-08-10..2022-09-05&type=Issues) | [@malemburg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amalemburg+updated%3A2022-08-10..2022-09-05&type=Issues) | [@manfromjupyter](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amanfromjupyter+updated%3A2022-08-10..2022-09-05&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-08-10..2022-09-05&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-08-10..2022-09-05&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2022-08-10..2022-09-05&type=Issues) | [@saulshanabrook](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asaulshanabrook+updated%3A2022-08-10..2022-09-05&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2022-08-10..2022-09-05&type=Issues) | [@tgeorgeux](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atgeorgeux+updated%3A2022-08-10..2022-09-05&type=Issues) | [@trallard](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrallard+updated%3A2022-08-10..2022-09-05&type=Issues) | [@VersBersh](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AVersBersh+updated%3A2022-08-10..2022-09-05&type=Issues) | [@vidartf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avidartf+updated%3A2022-08-10..2022-09-05&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-08-10..2022-09-05&type=Issues) -### 3.4.5 +## 3.4.5 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.4...385ea4be3d3e65e1f62d82e8bfedbe554736b2bb)) -#### Enhancements made +### Enhancements made - Add an option to enable "fast checks" of the jupyter lab build. [#12844](https://github.com/jupyterlab/jupyterlab/pull/12844) ([@thetorpedodog](https://github.com/thetorpedodog)) - Add .webp filetype in docRegistry. [#12839](https://github.com/jupyterlab/jupyterlab/pull/12839) ([@yangql176](https://github.com/yangql176)) -#### Bugs fixed +### Bugs fixed - Only show "Shut Down Kernel" if kernel is running [#12919](https://github.com/jupyterlab/jupyterlab/pull/12919) ([@krassowski](https://github.com/krassowski)) - Fix JSON Settings Editor [#12892](https://github.com/jupyterlab/jupyterlab/pull/12892) ([@krassowski](https://github.com/krassowski)) @@ -527,11 +1638,11 @@ - Fix kernel in the statusbar does not match the actual [#12865](https://github.com/jupyterlab/jupyterlab/pull/12865) ([@hsuanxyz](https://github.com/hsuanxyz)) - Adjust css to not leave trace of deleted widgets [#12838](https://github.com/jupyterlab/jupyterlab/pull/12838) ([@thomasaarholt](https://github.com/thomasaarholt)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Log launcher error to console [#12909](https://github.com/jupyterlab/jupyterlab/pull/12909) ([@trungleduc](https://github.com/trungleduc)) -#### Documentation improvements +### Documentation improvements - Add alt text to documentation [#12879](https://github.com/jupyterlab/jupyterlab/pull/12879) ([@isabela-pf](https://github.com/isabela-pf)) - Split commands in two blocks in the contributing guide [#12898](https://github.com/jupyterlab/jupyterlab/pull/12898) ([@jtpio](https://github.com/jtpio)) @@ -539,17 +1650,17 @@ - Document building JupyterLab on osx-arm64 platforms [#12882](https://github.com/jupyterlab/jupyterlab/pull/12882) ([@SylvainCorlay](https://github.com/SylvainCorlay)) - Don't suggest deprecated command [#12855](https://github.com/jupyterlab/jupyterlab/pull/12855) ([@ryanlovett](https://github.com/ryanlovett)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-07-21&to=2022-08-10&type=c)) [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-07-21..2022-08-10&type=Issues) | [@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2022-07-21..2022-08-10&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-07-21..2022-08-10&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-07-21..2022-08-10&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-07-21..2022-08-10&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-07-21..2022-08-10&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-07-21..2022-08-10&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-07-21..2022-08-10&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-07-21..2022-08-10&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-07-21..2022-08-10&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2022-07-21..2022-08-10&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-07-21..2022-08-10&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-07-21..2022-08-10&type=Issues) | [@ryanlovett](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aryanlovett+updated%3A2022-07-21..2022-08-10&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2022-07-21..2022-08-10&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2022-07-21..2022-08-10&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2022-07-21..2022-08-10&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-07-21..2022-08-10&type=Issues) -### 3.4.4 +## 3.4.4 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.3...998cf0e146fdb7c61c42d9487ebb89c16581faf8)) -#### Enhancements made +### Enhancements made - Adds version maintenance policy [#12829](https://github.com/jupyterlab/jupyterlab/pull/12829) ([@JasonWeill](https://github.com/JasonWeill)) - Increase title width in simple mode [#11546](https://github.com/jupyterlab/jupyterlab/pull/11546) ([@SylvainCorlay](https://github.com/SylvainCorlay)) @@ -558,7 +1669,7 @@ - Optimize debugger editor `eachLine` loops [#12746](https://github.com/jupyterlab/jupyterlab/pull/12746) ([@vidartf](https://github.com/vidartf)) - Make password inputs not give away how many characters were typed [#12659](https://github.com/jupyterlab/jupyterlab/pull/12659) ([@jasongrout](https://github.com/jasongrout)) -#### Bugs fixed +### Bugs fixed - Remove drive prefix from the file path when creating the new path [#12824](https://github.com/jupyterlab/jupyterlab/pull/12824) ([@hbcarlos](https://github.com/hbcarlos)) - Use path to extract `tmpPath` [#12823](https://github.com/jupyterlab/jupyterlab/pull/12823) ([@fcollonval](https://github.com/fcollonval)) @@ -572,7 +1683,7 @@ - Fix cell toolbar overlap in side-by-side render mode [#12710](https://github.com/jupyterlab/jupyterlab/pull/12710) ([@peytondmurray](https://github.com/peytondmurray)) - Remove ipywidgets message count in the execution indicator model [#12665](https://github.com/jupyterlab/jupyterlab/pull/12665) ([@trungleduc](https://github.com/trungleduc)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Update verdaccio, start registry on 0.0.0.0 [#12825](https://github.com/jupyterlab/jupyterlab/pull/12825) ([@fcollonval](https://github.com/fcollonval)) - Use Vega SVG renderer to drop canvas dependency [#12811](https://github.com/jupyterlab/jupyterlab/pull/12811) ([@fcollonval](https://github.com/fcollonval)) @@ -583,31 +1694,31 @@ - Bump version of `marked` and `@types/marked` [#12747](https://github.com/jupyterlab/jupyterlab/pull/12747) ([@krassowski](https://github.com/krassowski)) - Drop pre-commit from build dependencies (#12680) [#12706](https://github.com/jupyterlab/jupyterlab/pull/12706) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements - Adds version maintenance policy [#12829](https://github.com/jupyterlab/jupyterlab/pull/12829) ([@JasonWeill](https://github.com/JasonWeill)) - Explicitly set language to `en` in `conf.py` [#12712](https://github.com/jupyterlab/jupyterlab/pull/12712) ([@jtpio](https://github.com/jtpio)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-06-07&to=2022-07-21&type=c)) [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-06-07..2022-07-21&type=Issues) | [@aiqc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aaiqc+updated%3A2022-06-07..2022-07-21&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-06-07..2022-07-21&type=Issues) | [@dlqqq](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adlqqq+updated%3A2022-06-07..2022-07-21&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2022-06-07..2022-07-21&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-06-07..2022-07-21&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-06-07..2022-07-21&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-06-07..2022-07-21&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-06-07..2022-07-21&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2022-06-07..2022-07-21&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-06-07..2022-07-21&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-06-07..2022-07-21&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2022-06-07..2022-07-21&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-06-07..2022-07-21&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-06-07..2022-07-21&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-06-07..2022-07-21&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2022-06-07..2022-07-21&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-06-07..2022-07-21&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2022-06-07..2022-07-21&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-06-07..2022-07-21&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-06-07..2022-07-21&type=Issues) | [@siddartha-10](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asiddartha-10+updated%3A2022-06-07..2022-07-21&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2022-06-07..2022-07-21&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-06-07..2022-07-21&type=Issues) | [@williamstein](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awilliamstein+updated%3A2022-06-07..2022-07-21&type=Issues) -### 3.4.3 +## 3.4.3 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.2...b05da6fae42dcf5a5ad0dd9b46a8b75d64804799)) -#### New features added +### New features added - Persistent side-by-side ratio setting [#12633](https://github.com/jupyterlab/jupyterlab/pull/12633) ([@echarles](https://github.com/echarles)) -#### Enhancements made +### Enhancements made - Persistent side-by-side ratio setting [#12633](https://github.com/jupyterlab/jupyterlab/pull/12633) ([@echarles](https://github.com/echarles)) - Add "Open in Simple Mode" contextMenu option [#12577](https://github.com/jupyterlab/jupyterlab/pull/12577) ([@fcollonval](https://github.com/fcollonval)) -#### Bugs fixed +### Bugs fixed - Always check local packages against abspath [#10662](https://github.com/jupyterlab/jupyterlab/pull/10662) ([@mlucool](https://github.com/mlucool)) - Fix arrow position on unrendered markdown cell [#12660](https://github.com/jupyterlab/jupyterlab/pull/12660) ([@fcollonval](https://github.com/fcollonval)) @@ -618,72 +1729,123 @@ - Make selected text translucent so the cursor is visible in vim mode [#12520](https://github.com/jupyterlab/jupyterlab/pull/12520) ([@Jessie-Newman](https://github.com/Jessie-Newman)) - Fix file browser search highlighting bug [#12578](https://github.com/jupyterlab/jupyterlab/pull/12578) ([@fcollonval](https://github.com/fcollonval)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Fix failing check links [#12627](https://github.com/jupyterlab/jupyterlab/pull/12627) ([@jtpio](https://github.com/jtpio)) - Force crypto resolution [#12576](https://github.com/jupyterlab/jupyterlab/pull/12576) ([@fcollonval](https://github.com/fcollonval)) -#### Documentation improvements +### Documentation improvements - Add more explanation for internationalization (translation python package) [#12635](https://github.com/jupyterlab/jupyterlab/pull/12635) ([@a3626a](https://github.com/a3626a)) - Add "Open in Simple Mode" contextMenu option [#12577](https://github.com/jupyterlab/jupyterlab/pull/12577) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-05-13&to=2022-06-07&type=c)) [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-05-13..2022-06-07&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-05-13..2022-06-07&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-05-13..2022-06-07&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-05-13..2022-06-07&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2022-05-13..2022-06-07&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-05-13..2022-06-07&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-05-13..2022-06-07&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-05-13..2022-06-07&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-05-13..2022-06-07&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-05-13..2022-06-07&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-05-13..2022-06-07&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-05-13..2022-06-07&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-05-13..2022-06-07&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-05-13..2022-06-07&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-05-13..2022-06-07&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-05-13..2022-06-07&type=Issues) -### 3.4.2 +## 3.4.2 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.1...1c8f008679c49e74d8a4ee3c6aa0782dfa6a1d35)) -#### Bugs fixed +### Bugs fixed - Building extensions fail if not using latest patch [#12571](https://github.com/jupyterlab/jupyterlab/pull/12571) ([@ajbozarth](https://github.com/ajbozarth)) - fixed shouldOverwrite is never called when rename target exists [#12543](https://github.com/jupyterlab/jupyterlab/pull/12543) ([@ephes](https://github.com/ephes)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Update dependency version [#12535](https://github.com/jupyterlab/jupyterlab/pull/12535) ([@karlaspuldaro](https://github.com/karlaspuldaro)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-05-12&to=2022-05-12&type=c)) [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-05-12..2022-05-12&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-05-12..2022-05-12&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-05-12..2022-05-12&type=Issues) | [@karlaspuldaro](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akarlaspuldaro+updated%3A2022-05-12..2022-05-12&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-05-12..2022-05-12&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-05-12..2022-05-12&type=Issues) -### 3.4.1 +## 3.4.1 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.0...d8d94b351da08181d4d5e0493539c0eb082a1516)) -#### Enhancements made +### Enhancements made - Setting to use the advanced setting editor for the settings [#12466](https://github.com/jupyterlab/jupyterlab/pull/12466) ([@echarles](https://github.com/echarles)) -#### Bugs fixed +### Bugs fixed - Allow users to yarn link @jupyterlab/builder [#12533](https://github.com/jupyterlab/jupyterlab/pull/12533) ([@ajbozarth](https://github.com/ajbozarth)) - Get Auto Close Brackets working consistently in Consoles [#12508](https://github.com/jupyterlab/jupyterlab/pull/12508) ([@Jessie-Newman](https://github.com/Jessie-Newman)) - Handled new dialog creation with no buttons [#12496](https://github.com/jupyterlab/jupyterlab/pull/12496) ([@Jnnamchi](https://github.com/Jnnamchi)) - Handle missing `preferredPath` from the page config [#12521](https://github.com/jupyterlab/jupyterlab/pull/12521) ([@jtpio](https://github.com/jtpio)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Add cell-toolbar to CI and labeler [#12555](https://github.com/jupyterlab/jupyterlab/pull/12555) ([@fcollonval](https://github.com/fcollonval)) - Allow bot PRs to be automatically labeled [#12509](https://github.com/jupyterlab/jupyterlab/pull/12509) ([@blink1073](https://github.com/blink1073)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-05-03&to=2022-05-12&type=c)) [@ajbozarth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aajbozarth+updated%3A2022-05-03..2022-05-12&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-05-03..2022-05-12&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-05-03..2022-05-12&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-05-03..2022-05-12&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-05-03..2022-05-12&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-05-03..2022-05-12&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-05-03..2022-05-12&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-05-03..2022-05-12&type=Issues) -### 3.4.0 +## 3.4.0rc0 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.4...c394aa25d1845144ee7ebdce611ff12f8d962bb8)) + +### Enhancements made + +- Display default value in setting editor for changed values [#12468](https://github.com/jupyterlab/jupyterlab/pull/12468) ([@echarles](https://github.com/echarles)) +- Uses dark theme for Vega when JupyterLab theme is dark [#12411](https://github.com/jupyterlab/jupyterlab/pull/12411) ([@JasonWeill](https://github.com/JasonWeill)) +- Creates cell-toolbar, cell-toolbar-extension packages and populates toolbar [#12028](https://github.com/jupyterlab/jupyterlab/pull/12028) ([@JasonWeill](https://github.com/JasonWeill)) +- Customize the file browser toolbar via the settings [#12441](https://github.com/jupyterlab/jupyterlab/pull/12441) ([@fcollonval](https://github.com/fcollonval)) +- Wait until file browser commands are ready before activating file browser widget [#12435](https://github.com/jupyterlab/jupyterlab/pull/12435) ([@fcollonval](https://github.com/fcollonval)) +- Add a "New Tab" button that opens the launcher [#12195](https://github.com/jupyterlab/jupyterlab/pull/12195) ([@ajbozarth](https://github.com/ajbozarth)) +- Simplify galata import by proxying `expect` [#12311](https://github.com/jupyterlab/jupyterlab/pull/12311) ([@fcollonval](https://github.com/fcollonval)) +- Open terminal in cwd from launcher [#12250](https://github.com/jupyterlab/jupyterlab/pull/12250) ([@rccern](https://github.com/rccern)) +- Add support for filtering by field names in setting editor [#12082](https://github.com/jupyterlab/jupyterlab/pull/12082) ([@marthacryan](https://github.com/marthacryan)) +- Use transform to quickly switch between tabs. [#11074](https://github.com/jupyterlab/jupyterlab/pull/11074) ([@fcollonval](https://github.com/fcollonval)) +- Pop up select kernel dialog when run a cell without kernel [#12379](https://github.com/jupyterlab/jupyterlab/pull/12379) ([@a3626a](https://github.com/a3626a)) +- Allow LauncherModel to be more extendable [#12344](https://github.com/jupyterlab/jupyterlab/pull/12344) ([@ajbozarth](https://github.com/ajbozarth)) +- Add argument `searchText` and `replaceText` to search and replace commands [#12310](https://github.com/jupyterlab/jupyterlab/pull/12310) ([@fcollonval](https://github.com/fcollonval)) +- Add argument line and column to codemirror go to line command [#12204](https://github.com/jupyterlab/jupyterlab/pull/12204) ([@fcollonval](https://github.com/fcollonval)) +- Default is no virtual rendering + Relax virtual notebook rendering and ensure no structural change until rendering is completed [#12258](https://github.com/jupyterlab/jupyterlab/pull/12258) ([@echarles](https://github.com/echarles)) + +### Bugs fixed + +- Check if process is declared before optional chaining in makeSettings [#12472](https://github.com/jupyterlab/jupyterlab/pull/12472) ([@fcollonval](https://github.com/fcollonval)) +- Signal should only export ISignal publicly [#12471](https://github.com/jupyterlab/jupyterlab/pull/12471) ([@fcollonval](https://github.com/fcollonval)) +- Move cell toolbar below search document widget [#12467](https://github.com/jupyterlab/jupyterlab/pull/12467) ([@fcollonval](https://github.com/fcollonval)) +- Use css variable for font size. [#12255](https://github.com/jupyterlab/jupyterlab/pull/12255) ([@Carreau](https://github.com/Carreau)) + +### Maintenance and upkeep improvements + +- Only show duplicate LabIcon warning in debug mode [#12480](https://github.com/jupyterlab/jupyterlab/pull/12480) ([@ajbozarth](https://github.com/ajbozarth)) +- Update copyright date to 2022 in the about dialog [#12474](https://github.com/jupyterlab/jupyterlab/pull/12474) ([@jtpio](https://github.com/jtpio)) +- Fix update snapshot for 3.4.x [#12462](https://github.com/jupyterlab/jupyterlab/pull/12462) ([@fcollonval](https://github.com/fcollonval)) +- Update benchmark snapshots [#12451](https://github.com/jupyterlab/jupyterlab/pull/12451) ([@fcollonval](https://github.com/fcollonval)) + +### Documentation improvements + +- Creates cell-toolbar, cell-toolbar-extension packages and populates toolbar [#12028](https://github.com/jupyterlab/jupyterlab/pull/12028) ([@JasonWeill](https://github.com/JasonWeill)) +- Customize the file browser toolbar via the settings [#12441](https://github.com/jupyterlab/jupyterlab/pull/12441) ([@fcollonval](https://github.com/fcollonval)) + +### Deprecated features + +- Deprecate FileEditorCodeWrapper [#12381](https://github.com/jupyterlab/jupyterlab/pull/12381) ([@hbcarlos](https://github.com/hbcarlos)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-04-15&to=2022-04-28&type=c)) + +[@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-04-15..2022-04-28&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-04-15..2022-04-28&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-04-15..2022-04-28&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-04-15..2022-04-28&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2022-04-15..2022-04-28&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-04-15..2022-04-28&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-04-15..2022-04-28&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-04-15..2022-04-28&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2022-04-15..2022-04-28&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-04-15..2022-04-28&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-04-15..2022-04-28&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-04-15..2022-04-28&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-04-15..2022-04-28&type=Issues) + +## 3.4.0 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.4...06e043de7cc211e360711fd042b6b474e9b0037b)) -#### Enhancements made +### Enhancements made - Add ability to open settings editor to specific plugin's settings [#12506](https://github.com/jupyterlab/jupyterlab/pull/12506) ([@fcollonval](https://github.com/fcollonval)) - Don't sort context menu items by selector [#12505](https://github.com/jupyterlab/jupyterlab/pull/12505) ([@fcollonval](https://github.com/fcollonval)) @@ -704,7 +1866,7 @@ - Add argument line and column to codemirror go to line command [#12204](https://github.com/jupyterlab/jupyterlab/pull/12204) ([@fcollonval](https://github.com/fcollonval)) - Default is no virtual rendering + Relax virtual notebook rendering and ensure no structural change until rendering is completed [#12258](https://github.com/jupyterlab/jupyterlab/pull/12258) ([@echarles](https://github.com/echarles)) -#### Bugs fixed +### Bugs fixed - Ensure settings editor is attached before activation [#12507](https://github.com/jupyterlab/jupyterlab/pull/12507) ([@fcollonval](https://github.com/fcollonval)) - Setting form editor has a formState to avoid focus lost [#12470](https://github.com/jupyterlab/jupyterlab/pull/12470) ([@echarles](https://github.com/echarles)) @@ -713,23 +1875,23 @@ - Move cell toolbar below search document widget [#12467](https://github.com/jupyterlab/jupyterlab/pull/12467) ([@fcollonval](https://github.com/fcollonval)) - Use css variable for font size. [#12255](https://github.com/jupyterlab/jupyterlab/pull/12255) ([@Carreau](https://github.com/Carreau)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Only show duplicate LabIcon warning in debug mode [#12480](https://github.com/jupyterlab/jupyterlab/pull/12480) ([@ajbozarth](https://github.com/ajbozarth)) - Update copyright date to 2022 in the about dialog [#12474](https://github.com/jupyterlab/jupyterlab/pull/12474) ([@jtpio](https://github.com/jtpio)) - Fix update snapshot for 3.4.x [#12462](https://github.com/jupyterlab/jupyterlab/pull/12462) ([@fcollonval](https://github.com/fcollonval)) - Update benchmark snapshots [#12451](https://github.com/jupyterlab/jupyterlab/pull/12451) ([@fcollonval](https://github.com/fcollonval)) -#### Documentation improvements +### Documentation improvements - Creates cell-toolbar, cell-toolbar-extension packages and populates toolbar [#12028](https://github.com/jupyterlab/jupyterlab/pull/12028) ([@JasonWeill](https://github.com/JasonWeill)) - Customize the file browser toolbar via the settings [#12441](https://github.com/jupyterlab/jupyterlab/pull/12441) ([@fcollonval](https://github.com/fcollonval)) -#### Deprecated features +### Deprecated features - Deprecate FileEditorCodeWrapper [#12381](https://github.com/jupyterlab/jupyterlab/pull/12381) ([@hbcarlos](https://github.com/hbcarlos)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-04-15&to=2022-05-03&type=c)) @@ -737,15 +1899,15 @@ ## v3.3 -### 3.3.4 +## 3.3.4 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.3...a8a438b3bd84806b8e186e7e037d73167d371c3a)) -#### Enhancements made +### Enhancements made - Type-only and lazy imports of settings widgets [#12372](https://github.com/jupyterlab/jupyterlab/pull/12372) ([@fcollonval](https://github.com/fcollonval)) -#### Bugs fixed +### Bugs fixed - Position collapse heading button next to corresponding h tag (jupyterâ€Ļ) [#12412](https://github.com/jupyterlab/jupyterlab/pull/12412) ([@fcollonval](https://github.com/fcollonval)) - Toolbar items may not act on the proper target [#12368](https://github.com/jupyterlab/jupyterlab/pull/12368) ([@fcollonval](https://github.com/fcollonval)) @@ -756,33 +1918,33 @@ - Remove circular setting of source [#12338](https://github.com/jupyterlab/jupyterlab/pull/12338) ([@hbcarlos](https://github.com/hbcarlos)) - Protect against undefined delegated label [#10972](https://github.com/jupyterlab/jupyterlab/pull/10972) ([@fcollonval](https://github.com/fcollonval)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Use pre-commit [#12404](https://github.com/jupyterlab/jupyterlab/pull/12404) ([@fcollonval](https://github.com/fcollonval)) - Update Playwright snapshots from PR comments [#12403](https://github.com/jupyterlab/jupyterlab/pull/12403) ([@fcollonval](https://github.com/fcollonval)) - Bump moment from 2.29.1 to 2.29.2 [#12389](https://github.com/jupyterlab/jupyterlab/pull/12389) ([@fcollonval](https://github.com/fcollonval)) -#### Documentation improvements +### Documentation improvements - Fix GitHub link [#12410](https://github.com/jupyterlab/jupyterlab/pull/12410) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-04-07&to=2022-04-15&type=c)) [@aiqc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aaiqc+updated%3A2022-04-07..2022-04-15&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-04-07..2022-04-15&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-04-07..2022-04-15&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-04-07..2022-04-15&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-04-07..2022-04-15&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-04-07..2022-04-15&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-04-07..2022-04-15&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-04-07..2022-04-15&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2022-04-07..2022-04-15&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-04-07..2022-04-15&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-04-07..2022-04-15&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-04-07..2022-04-15&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-04-07..2022-04-15&type=Issues) -### 3.3.3 +## 3.3.3 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.2...d97ff7161640634f69e70b184b9e255a68620f95)) -#### Enhancements made +### Enhancements made - Add a preferred-dir icon to the file browser crumbs [#12354](https://github.com/jupyterlab/jupyterlab/pull/12354) ([@echarles](https://github.com/echarles)) - Adds preferKernel option to JupyterLab code [#12260](https://github.com/jupyterlab/jupyterlab/pull/12260) ([@JasonWeill](https://github.com/JasonWeill)) - Add aria progressbar role and data-status for testing in extensions [#12238](https://github.com/jupyterlab/jupyterlab/pull/12238) ([@krassowski](https://github.com/krassowski)) -#### Bugs fixed +### Bugs fixed - Fix Markdown cell generates duplicate toc content (#12312) [#12314](https://github.com/jupyterlab/jupyterlab/pull/12314) ([@yangql176](https://github.com/yangql176)) - Fix settings with `null` default not getting marked as modified [#12240](https://github.com/jupyterlab/jupyterlab/pull/12240) ([@krassowski](https://github.com/krassowski)) @@ -792,75 +1954,75 @@ - Fix state restoration in the notebook extension [#12218](https://github.com/jupyterlab/jupyterlab/pull/12218) ([@jtpio](https://github.com/jtpio)) - Fix sdist editable install and add tests [#12224](https://github.com/jupyterlab/jupyterlab/pull/12224) ([@blink1073](https://github.com/blink1073)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - \[3.3.x\] Add git-blame-ignore-revs file [#12289](https://github.com/jupyterlab/jupyterlab/pull/12289) ([@blink1073](https://github.com/blink1073)) - \[3.3.x\] Run black [#12282](https://github.com/jupyterlab/jupyterlab/pull/12282) ([@blink1073](https://github.com/blink1073)) - Stop using py.test [#12262](https://github.com/jupyterlab/jupyterlab/pull/12262) ([@fcollonval](https://github.com/fcollonval)) - Inline `expected_http_error` function from `jupyterlab_server.tests` [#12228](https://github.com/jupyterlab/jupyterlab/pull/12228) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements - \[3.3.x\] Run black [#12282](https://github.com/jupyterlab/jupyterlab/pull/12282) ([@blink1073](https://github.com/blink1073)) - Stop using py.test [#12262](https://github.com/jupyterlab/jupyterlab/pull/12262) ([@fcollonval](https://github.com/fcollonval)) - Update link to `jupyterlab-some-package` in docs [#12248](https://github.com/jupyterlab/jupyterlab/pull/12248) ([@jtpio](https://github.com/jtpio)) - Update command in Performance Testing to use the right option [#12215](https://github.com/jupyterlab/jupyterlab/pull/12215) ([@JasonWeill](https://github.com/JasonWeill)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-03-14&to=2022-04-07&type=c)) [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-03-14..2022-04-07&type=Issues) | [@aiqc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aaiqc+updated%3A2022-03-14..2022-04-07&type=Issues) | [@ajbozarth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aajbozarth+updated%3A2022-03-14..2022-04-07&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-03-14..2022-04-07&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-03-14..2022-04-07&type=Issues) | [@damianavila](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adamianavila+updated%3A2022-03-14..2022-04-07&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-03-14..2022-04-07&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-03-14..2022-04-07&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-03-14..2022-04-07&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-03-14..2022-04-07&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-03-14..2022-04-07&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2022-03-14..2022-04-07&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-03-14..2022-04-07&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-03-14..2022-04-07&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2022-03-14..2022-04-07&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-03-14..2022-04-07&type=Issues) | [@marthacryan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarthacryan+updated%3A2022-03-14..2022-04-07&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2022-03-14..2022-04-07&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-03-14..2022-04-07&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-03-14..2022-04-07&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2022-03-14..2022-04-07&type=Issues) | [@rccern](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Arccern+updated%3A2022-03-14..2022-04-07&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-03-14..2022-04-07&type=Issues) -### 3.3.2 +## 3.3.2 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.1...5abe7f69837af8c349d5448f6f3e70db6c48c6e0)) -#### Bugs fixed +### Bugs fixed - Remove use of ipython_genutils [#12202](https://github.com/jupyterlab/jupyterlab/pull/12202) ([@blink1073](https://github.com/blink1073)) -#### Documentation improvements +### Documentation improvements - Add note about `async`, `await` and `Promises` in the extension tutorial [#12199](https://github.com/jupyterlab/jupyterlab/pull/12199) ([@jtpio](https://github.com/jtpio)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-03-09&to=2022-03-14&type=c)) [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-03-09..2022-03-14&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-03-09..2022-03-14&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-03-09..2022-03-14&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-03-09..2022-03-14&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-03-09..2022-03-14&type=Issues) -### 3.3.1 +## 3.3.1 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.0...a51e1110263c28211ed9e8e0a4bba247c828af94)) -#### Enhancements made +### Enhancements made - Add a note to command line option that collaborative mode is experimental [#12173](https://github.com/jupyterlab/jupyterlab/pull/12173) ([@jasongrout](https://github.com/jasongrout)) - Adds warning that RTC is experimental [#12171](https://github.com/jupyterlab/jupyterlab/pull/12171) ([@JasonWeill](https://github.com/JasonWeill)) - Export KernelConnection [#12156](https://github.com/jupyterlab/jupyterlab/pull/12156) ([@tkrabel-db](https://github.com/tkrabel-db)) -#### Bugs fixed +### Bugs fixed - Backport PR #12122: Remove duplicated shortcuts [#12181](https://github.com/jupyterlab/jupyterlab/pull/12181) ([@fcollonval](https://github.com/fcollonval)) - Correct the set item logic of `CodeCellModel.onModelDBOutputsChange` [#12147](https://github.com/jupyterlab/jupyterlab/pull/12147) ([@trungleduc](https://github.com/trungleduc)) - fix: typo in ShortcutItem component [#12161](https://github.com/jupyterlab/jupyterlab/pull/12161) ([@sparanoid](https://github.com/sparanoid)) -#### Documentation improvements +### Documentation improvements - Adds warning that RTC is experimental [#12171](https://github.com/jupyterlab/jupyterlab/pull/12171) ([@JasonWeill](https://github.com/JasonWeill)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-03-02&to=2022-03-09&type=c)) [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-03-02..2022-03-09&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-03-02..2022-03-09&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-03-02..2022-03-09&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-03-02..2022-03-09&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-03-02..2022-03-09&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-03-02..2022-03-09&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-03-02..2022-03-09&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-03-02..2022-03-09&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2022-03-02..2022-03-09&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-03-02..2022-03-09&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2022-03-02..2022-03-09&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-03-02..2022-03-09&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-03-02..2022-03-09&type=Issues) -### 3.3.0 +## 3.3.0 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.5...6e484f89df73e09c29e8608e5eca88fa48cc4267)) -#### Enhancements made +### Enhancements made - Document search debounce time via setting [#12121](https://github.com/jupyterlab/jupyterlab/pull/12121) ([@fcollonval](https://github.com/fcollonval)) - Improve toggled button styles in debugger. [#12120](https://github.com/jupyterlab/jupyterlab/pull/12120) ([@fcollonval](https://github.com/fcollonval)) @@ -892,7 +2054,7 @@ - Fix overlapped shadow for scrolling output cell [#11785](https://github.com/jupyterlab/jupyterlab/pull/11785) ([@thesinepainter](https://github.com/thesinepainter)) - Toggle side-by-side rendering for current notebook (#11793) [#11794](https://github.com/jupyterlab/jupyterlab/pull/11794) ([@fcollonval](https://github.com/fcollonval)) -#### Bugs fixed +### Bugs fixed - Build UMD module for @jupyterlab/services [#12141](https://github.com/jupyterlab/jupyterlab/pull/12141) ([@fcollonval](https://github.com/fcollonval)) - Fix broken link in docs [#12138](https://github.com/jupyterlab/jupyterlab/pull/12138) ([@JasonWeill](https://github.com/JasonWeill)) @@ -918,7 +2080,7 @@ - Specify an output hash function for Galata [#11830](https://github.com/jupyterlab/jupyterlab/pull/11830) ([@jasongrout](https://github.com/jasongrout)) - Preserve breakpoint gutter when cells are moved. [#11766](https://github.com/jupyterlab/jupyterlab/pull/11766) ([@fcollonval](https://github.com/fcollonval)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Parse URL parameters in user model [#12065](https://github.com/jupyterlab/jupyterlab/pull/12065) ([@fcollonval](https://github.com/fcollonval)) - Update vscode-debugprotocol to @vscode/debugprotocol [#11953](https://github.com/jupyterlab/jupyterlab/pull/11953) ([@fcollonval](https://github.com/fcollonval)) @@ -930,7 +2092,7 @@ - Update reference snapshot for the completer UI test [#11846](https://github.com/jupyterlab/jupyterlab/pull/11846) ([@jtpio](https://github.com/jtpio)) - Bump version for the 3.3 prerelease [#11810](https://github.com/jupyterlab/jupyterlab/pull/11810) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements - Fix broken link in docs [#12138](https://github.com/jupyterlab/jupyterlab/pull/12138) ([@JasonWeill](https://github.com/JasonWeill)) - Fix anchors and myst configuration [#12063](https://github.com/jupyterlab/jupyterlab/pull/12063) ([@fcollonval](https://github.com/fcollonval)) @@ -943,14 +2105,14 @@ - Add `3.1.19` Changelog Entry [#11842](https://github.com/jupyterlab/jupyterlab/pull/11842) ([@jtpio](https://github.com/jtpio)) - Give conda instructions for the pixman pkg-config error. [#11829](https://github.com/jupyterlab/jupyterlab/pull/11829) ([@jasongrout](https://github.com/jasongrout)) -#### API and Breaking Changes +### API and Breaking Changes - Toc running cell indicator [#11804](https://github.com/jupyterlab/jupyterlab/pull/11804) ([@andrewfulton9](https://github.com/andrewfulton9)) - Toggle side-by-side rendering for current notebook (#11793) [#11794](https://github.com/jupyterlab/jupyterlab/pull/11794) ([@fcollonval](https://github.com/fcollonval)) -#### Other merged PRs +### Other merged PRs -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-12-10&to=2022-03-02&type=c)) @@ -958,60 +2120,60 @@ ## v3.2 -### 3.2.9 +## 3.2.9 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.8...dbfc96a51c872288f16b7340398bf99a3df14b1f)) -#### Bugs fixed +### Bugs fixed - overrides.json definition takes precedence [#11980](https://github.com/jupyterlab/jupyterlab/pull/11980) ([@fcollonval](https://github.com/fcollonval)) - Fix autocomplete in console [#11949](https://github.com/jupyterlab/jupyterlab/pull/11949) ([@fcollonval](https://github.com/fcollonval)) - Add percent decoding to username [#11865](https://github.com/jupyterlab/jupyterlab/pull/11865) ([@fcollonval](https://github.com/fcollonval)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Use `maintainer-tools` base setup action [#11595](https://github.com/jupyterlab/jupyterlab/pull/11595) ([@jtpio](https://github.com/jtpio)) - Drop testing Python 3.6, test on Python 3.10 [#11646](https://github.com/jupyterlab/jupyterlab/pull/11646) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements - Update screenshots and text for user interface docs [#11981](https://github.com/jupyterlab/jupyterlab/pull/11981) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-01-13&to=2022-02-04&type=c)) [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2022-01-13..2022-02-04&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-01-13..2022-02-04&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-01-13..2022-02-04&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-01-13..2022-02-04&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-01-13..2022-02-04&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-01-13..2022-02-04&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-01-13..2022-02-04&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2022-01-13..2022-02-04&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-01-13..2022-02-04&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2022-01-13..2022-02-04&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-01-13..2022-02-04&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-01-13..2022-02-04&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-01-13..2022-02-04&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-01-13..2022-02-04&type=Issues) | [@marthacryan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarthacryan+updated%3A2022-01-13..2022-02-04&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-01-13..2022-02-04&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-01-13..2022-02-04&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2022-01-13..2022-02-04&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-01-13..2022-02-04&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2022-01-13..2022-02-04&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AZsailer+updated%3A2022-01-13..2022-02-04&type=Issues) -### 3.2.8 +## 3.2.8 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.7...b2402e5b9e0db0416b5f0e5ac29c9104a69f0c83)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Use the root yarn.lock in staging when making a release. [#11433](https://github.com/jupyterlab/jupyterlab/pull/11433) ([@jasongrout](https://github.com/jasongrout)) - Update reference snapshot for the completer UI test [#11847](https://github.com/jupyterlab/jupyterlab/pull/11847) ([@jtpio](https://github.com/jtpio)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-01-12&to=2022-01-13&type=c)) [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-01-12..2022-01-13&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-01-12..2022-01-13&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-01-12..2022-01-13&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-01-12..2022-01-13&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-01-12..2022-01-13&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-01-12..2022-01-13&type=Issues) -### 3.2.7 +## 3.2.7 No merged PRs -### 3.2.6 +## 3.2.6 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.5...ebce458c5e55126a7cbd5082f669446269007a34)) -#### Enhancements made +### Enhancements made - Add JSX CodeMirror mode [#11666](https://github.com/jupyterlab/jupyterlab/pull/11666) ([@krassowski](https://github.com/krassowski)) - Remove leading slash from console path [#11626](https://github.com/jupyterlab/jupyterlab/pull/11626) ([@davidbrochart](https://github.com/davidbrochart)) -#### Bugs fixed +### Bugs fixed - Restore compact notebook layout on mobile [#11778](https://github.com/jupyterlab/jupyterlab/pull/11778) ([@jtpio](https://github.com/jtpio)) - Ensure browser attributes are set in plugin adding it [#11758](https://github.com/jupyterlab/jupyterlab/pull/11758) ([@fcollonval](https://github.com/fcollonval)) @@ -1020,38 +2182,38 @@ No merged PRs - Ensure the dialog does not close if you drag outside by mistake [#11673](https://github.com/jupyterlab/jupyterlab/pull/11673) ([@echarles](https://github.com/echarles)) - Add JSX CodeMirror mode [#11666](https://github.com/jupyterlab/jupyterlab/pull/11666) ([@krassowski](https://github.com/krassowski)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Revert "Toggle side-by-side rendering for current notebook" [#11793](https://github.com/jupyterlab/jupyterlab/pull/11793) ([@fcollonval](https://github.com/fcollonval)) - Fix integrity failure on CI [#11770](https://github.com/jupyterlab/jupyterlab/pull/11770) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements - Triage documentation [#11661](https://github.com/jupyterlab/jupyterlab/pull/11661) ([@JasonWeill](https://github.com/JasonWeill)) - Add text on how to run it in a dir other than home [#11761](https://github.com/jupyterlab/jupyterlab/pull/11761) ([@TheOtherRealm](https://github.com/TheOtherRealm)) - Encourage new contributors to send draft PR over asking for permission [#11746](https://github.com/jupyterlab/jupyterlab/pull/11746) ([@krassowski](https://github.com/krassowski)) - Fix changelog link [#11668](https://github.com/jupyterlab/jupyterlab/pull/11668) ([@krassowski](https://github.com/krassowski)) -#### Other merged PRs +### Other merged PRs - Toggle side-by-side rendering for current notebook [#11718](https://github.com/jupyterlab/jupyterlab/pull/11718) ([@echarles](https://github.com/echarles)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-12-10&to=2022-01-07&type=c)) [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2021-12-10..2022-01-07&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-12-10..2022-01-07&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-12-10..2022-01-07&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-12-10..2022-01-07&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-12-10..2022-01-07&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-12-10..2022-01-07&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-12-10..2022-01-07&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-12-10..2022-01-07&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-12-10..2022-01-07&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2021-12-10..2022-01-07&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-12-10..2022-01-07&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-12-10..2022-01-07&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-12-10..2022-01-07&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-12-10..2022-01-07&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-12-10..2022-01-07&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-12-10..2022-01-07&type=Issues) | [@schmidi314](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aschmidi314+updated%3A2021-12-10..2022-01-07&type=Issues) | [@TheOtherRealm](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ATheOtherRealm+updated%3A2021-12-10..2022-01-07&type=Issues) | [@thesinepainter](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Athesinepainter+updated%3A2021-12-10..2022-01-07&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-12-10..2022-01-07&type=Issues) -### 3.2.5 +## 3.2.5 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.4...97b8069f014c51f584c86165ec0aff8c98be99cb)) -#### Enhancements made +### Enhancements made - Tweak CSS for scrolled outputs [#11478](https://github.com/jupyterlab/jupyterlab/pull/11478) ([@jtpio](https://github.com/jtpio)) - Add side-by-side rendering as global setting [#11533](https://github.com/jupyterlab/jupyterlab/pull/11533) ([@jess-x](https://github.com/jess-x)) -#### Bugs fixed +### Bugs fixed - Fix menu items for toc [#11634](https://github.com/jupyterlab/jupyterlab/pull/11634) ([@fcollonval](https://github.com/fcollonval)) - Restore accidentally removed ToC context menu [#11617](https://github.com/jupyterlab/jupyterlab/pull/11617) ([@krassowski](https://github.com/krassowski)) @@ -1068,7 +2230,7 @@ No merged PRs - Fix Tex highlights affecting Markdown with standalone `$` [#11488](https://github.com/jupyterlab/jupyterlab/pull/11488) ([@krassowski](https://github.com/krassowski)) - Fix malformed fenced code block Markdown rendering [#11479](https://github.com/jupyterlab/jupyterlab/pull/11479) ([@krassowski](https://github.com/krassowski)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Explicitly build JupyterLab in dev-mode [#11585](https://github.com/jupyterlab/jupyterlab/pull/11585) ([@fcollonval](https://github.com/fcollonval)) - Fix markdown benchmark snapshot [#11575](https://github.com/jupyterlab/jupyterlab/pull/11575) ([@fcollonval](https://github.com/fcollonval)) @@ -1079,26 +2241,26 @@ No merged PRs - Run UI test on 3.2.x push [#11521](https://github.com/jupyterlab/jupyterlab/pull/11521) ([@fcollonval](https://github.com/fcollonval)) - Enforce labels on PRs [#11496](https://github.com/jupyterlab/jupyterlab/pull/11496) ([@blink1073](https://github.com/blink1073)) -#### Documentation +### Documentation - Missing parenthesis [#11590](https://github.com/jupyterlab/jupyterlab/pull/11590) ([@davidbrochart](https://github.com/davidbrochart)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-11-17&to=2021-12-10&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-11-17..2021-12-10&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-11-17..2021-12-10&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-11-17..2021-12-10&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-11-17..2021-12-10&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-11-17..2021-12-10&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-11-17..2021-12-10&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-11-17..2021-12-10&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-11-17..2021-12-10&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-11-17..2021-12-10&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-11-17..2021-12-10&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-11-17..2021-12-10&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-11-17..2021-12-10&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-11-17..2021-12-10&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2021-11-17..2021-12-10&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-11-17..2021-12-10&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-11-17..2021-12-10&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-11-17..2021-12-10&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-11-17..2021-12-10&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-11-17..2021-12-10&type=Issues) -### 3.2.4 +## 3.2.4 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.3...3bf36235a2521944b2b0b034e7986630ee83de18)) -#### Enhancements made +### Enhancements made - Recommend trying prebuilt extension version in the build failure dialog [#11476](https://github.com/jupyterlab/jupyterlab/pull/11476) ([@krassowski](https://github.com/krassowski)) - Run comparative benchmark [#11441](https://github.com/jupyterlab/jupyterlab/pull/11441) ([@fcollonval](https://github.com/fcollonval)) -#### Bugs fixed +### Bugs fixed - Add background to the reference iframes to fix contrast [#11477](https://github.com/jupyterlab/jupyterlab/pull/11477) ([@krassowski](https://github.com/krassowski)) - Fix `undomanager` paste regression - fixes #10928 [#11471](https://github.com/jupyterlab/jupyterlab/pull/11471) ([@dmonad](https://github.com/dmonad)) @@ -1106,46 +2268,46 @@ No merged PRs - Fix browser tab name [#10952](https://github.com/jupyterlab/jupyterlab/pull/10952) ([@tejasmorkar](https://github.com/tejasmorkar)) - Do not update contextual help inspector if there would be no change. [#11447](https://github.com/jupyterlab/jupyterlab/pull/11447) ([@jasongrout](https://github.com/jasongrout)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Reduce flake on non-LaTeX highlighting test [#11470](https://github.com/jupyterlab/jupyterlab/pull/11470) ([@krassowski](https://github.com/krassowski)) - Makes restorer parameter optional in `toc-extension` [#11460](https://github.com/jupyterlab/jupyterlab/pull/11460) ([@fcollonval](https://github.com/fcollonval)) - Enforce ascii-only identifiers [#11449](https://github.com/jupyterlab/jupyterlab/pull/11449) ([@jasongrout](https://github.com/jasongrout)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-11-11&to=2021-11-17&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-11-11..2021-11-17&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-11-11..2021-11-17&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-11-11..2021-11-17&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-11-11..2021-11-17&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-11-11..2021-11-17&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-11-11..2021-11-17&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-11-11..2021-11-17&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-11-11..2021-11-17&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-11-11..2021-11-17&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-11-11..2021-11-17&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-11-11..2021-11-17&type=Issues) | [@williamstein](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awilliamstein+updated%3A2021-11-11..2021-11-17&type=Issues) -### 3.2.3 +## 3.2.3 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.2...49b2dfa5b74d5139dcbc55940ee5ed93b48e9db2)) -#### Enhancements made +### Enhancements made - \[3.2.x\] Expose `window.jupyterapp` [#11417](https://github.com/jupyterlab/jupyterlab/pull/11417) ([@jtpio](https://github.com/jtpio)) -#### Bugs fixed +### Bugs fixed - Handle relative paths to `themePath` and `schemaDir` [#11427](https://github.com/jupyterlab/jupyterlab/pull/11427) ([@jtpio](https://github.com/jtpio)) - Backport PR #11398 on branch 3.2.x (fix #11377 & bump Yjs dependencies & fix modeldb overwriting yjs content) [#11408](https://github.com/jupyterlab/jupyterlab/pull/11408) ([@dmonad](https://github.com/dmonad)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Backport PR #11420 on branch 3.2.x (Makes ILabShell optional in toc extension) [#11421](https://github.com/jupyterlab/jupyterlab/pull/11421) ([@JasonWeill](https://github.com/JasonWeill)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-11-04&to=2021-11-11&type=c)) [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-11-04..2021-11-11&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-11-04..2021-11-11&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-11-04..2021-11-11&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-11-04..2021-11-11&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-11-04..2021-11-11&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-11-04..2021-11-11&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2021-11-04..2021-11-11&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-11-04..2021-11-11&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-11-04..2021-11-11&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-11-04..2021-11-11&type=Issues) -### 3.2.2 +## 3.2.2 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.1...0fcd2f5bfbe857a416dfad0c177f3f1299fef96e)) -#### Bugs fixed +### Bugs fixed - Make `orig_nbformat` optional #11005 [#11370](https://github.com/jupyterlab/jupyterlab/pull/11370) ([@nanoant](https://github.com/nanoant)) - Updated dialog with text to a reasonable width [#11331](https://github.com/jupyterlab/jupyterlab/pull/11331) ([@3coins](https://github.com/3coins)) @@ -1153,13 +2315,13 @@ No merged PRs - Only trigger dirty status update on value changes [#11346](https://github.com/jupyterlab/jupyterlab/pull/11346) ([@krassowski](https://github.com/krassowski)) - Run nested code cells directly from markdown headings [#11375](https://github.com/jupyterlab/jupyterlab/pull/11375) ([@jess-x](https://github.com/jess-x)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Fix `release_test` [#11390](https://github.com/jupyterlab/jupyterlab/pull/11390) ([@fcollonval](https://github.com/fcollonval)) - Removed `cat package.json` [#11372](https://github.com/jupyterlab/jupyterlab/pull/11372) ([@ceesu](https://github.com/ceesu)) - Relax `@playright/test` dependency in Galata [#11371](https://github.com/jupyterlab/jupyterlab/pull/11371) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements - Fix links [#11378](https://github.com/jupyterlab/jupyterlab/pull/11378) ([@krassowski](https://github.com/krassowski)) - Adds command to docs to install canvas dependencies [#11365](https://github.com/jupyterlab/jupyterlab/pull/11365) ([@JasonWeill](https://github.com/JasonWeill)) @@ -1167,17 +2329,17 @@ No merged PRs - Fix outdated `clearSignalData` reference (now `Signal.clearData`) [#11339](https://github.com/jupyterlab/jupyterlab/pull/11339) ([@krassowski](https://github.com/krassowski)) - Improve documentation on galata setup [#11391](https://github.com/jupyterlab/jupyterlab/pull/11391) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-10-20&to=2021-11-04&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-10-20..2021-11-04&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-10-20..2021-11-04&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-10-20..2021-11-04&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-10-20..2021-11-04&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-10-20..2021-11-04&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-10-20..2021-11-04&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-10-20..2021-11-04&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-10-20..2021-11-04&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-10-20..2021-11-04&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-10-20..2021-11-04&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-10-20..2021-11-04&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-10-20..2021-11-04&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-10-20..2021-11-04&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-10-20..2021-11-04&type=Issues) | [@williamstein](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awilliamstein+updated%3A2021-10-20..2021-11-04&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AZsailer+updated%3A2021-10-20..2021-11-04&type=Issues) -### 3.2.1 +## 3.2.1 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.0...2b7e4ea681ad11b2df16124b588448aac9562aef)) -#### Bugs fixed +### Bugs fixed - Updated button styles to accessible colors [#11321](https://github.com/jupyterlab/jupyterlab/pull/11321) ([@3coins](https://github.com/3coins)) - Fix for debugger not working for scripts [#11311](https://github.com/jupyterlab/jupyterlab/pull/11311) ([@3coins](https://github.com/3coins)) @@ -1185,29 +2347,29 @@ No merged PRs - Emit `indexChanged` on model state updates [#11298](https://github.com/jupyterlab/jupyterlab/pull/11298) ([@krassowski](https://github.com/krassowski)) - Fix ANSI vs URL conflict, prefix `www.` with `https://` [#11272](https://github.com/jupyterlab/jupyterlab/pull/11272) ([@krassowski](https://github.com/krassowski)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Pass version spec as an input [#11322](https://github.com/jupyterlab/jupyterlab/pull/11322) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements - Updated button styles to accessible colors [#11321](https://github.com/jupyterlab/jupyterlab/pull/11321) ([@3coins](https://github.com/3coins)) - Add note on the server parameter for hidden files. [#11293](https://github.com/jupyterlab/jupyterlab/pull/11293) ([@fcollonval](https://github.com/fcollonval)) - Amend changelog - follow up issue 11304 [#11309](https://github.com/jupyterlab/jupyterlab/pull/11309) ([@achimgaedke](https://github.com/achimgaedke)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-10-14&to=2021-10-20&type=c)) [@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-10-14..2021-10-20&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-10-14..2021-10-20&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-10-14..2021-10-20&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-10-14..2021-10-20&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-10-14..2021-10-20&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-10-14..2021-10-20&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-10-14..2021-10-20&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-10-14..2021-10-20&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-10-14..2021-10-20&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-10-14..2021-10-20&type=Issues) -### 3.2.0 +## 3.2.0 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/@jupyterlab/example-services-outputarea@3.1.9...2444ed0588adba1999a5575304d452a3b512c913)) -#### Enhancements made +### Enhancements made -- Add a menu entry to show/hide hidden files in the filebrowser [#11206](https://github.com/jupyterlab/jupyterlab/pull/11206) ([@loichuder](https://github.com/loichuder)) - activation instructions: [see documentation](https://jupyterlab.readthedocs.io/en/3.6.x/user/files.html#displaying-hidden-files) +- Add a menu entry to show/hide hidden files in the filebrowser [#11206](https://github.com/jupyterlab/jupyterlab/pull/11206) ([@loichuder](https://github.com/loichuder)) - activation instructions: [see documentation](https://jupyterlab.readthedocs.io/en/stable/user/files.html#displaying-hidden-files) - Restore Copy shareable link use of `shareUrl` [#11188](https://github.com/jupyterlab/jupyterlab/pull/11188) ([@fcollonval](https://github.com/fcollonval)) - Add Galata in JupyterLab [#11179](https://github.com/jupyterlab/jupyterlab/pull/11179) ([@fcollonval](https://github.com/fcollonval)) - Responsive Toolbar [#11178](https://github.com/jupyterlab/jupyterlab/pull/11178) ([@3coins](https://github.com/3coins)) @@ -1220,7 +2382,7 @@ No merged PRs - Enable disabling document-wide history tracking [#10949](https://github.com/jupyterlab/jupyterlab/pull/10949) ([@echarles](https://github.com/echarles)) - Removed debug switch [#11185](https://github.com/jupyterlab/jupyterlab/pull/11185) ([@3coins](https://github.com/3coins)) -#### Bugs fixed +### Bugs fixed - Normalize cell source `\r` line endings [#11271](https://github.com/jupyterlab/jupyterlab/pull/11271) ([@jasongrout](https://github.com/jasongrout)) - Fix Webpack crypto handling [#11249](https://github.com/jupyterlab/jupyterlab/pull/11249) ([@blink1073](https://github.com/blink1073)) @@ -1235,7 +2397,7 @@ No merged PRs - Fix auto close brackets for console [#11137](https://github.com/jupyterlab/jupyterlab/pull/11137) ([@ohrely](https://github.com/ohrely)) - Add a guard to avoid kernel deadlock on multiple input request [#10792](https://github.com/jupyterlab/jupyterlab/pull/10792) ([@echarles](https://github.com/echarles)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Extension upgrade script: Avoid throwing exceptions for certain package.json files [#11278](https://github.com/jupyterlab/jupyterlab/pull/11278) ([@ammgws](https://github.com/ammgws)) - Run Linter [#11238](https://github.com/jupyterlab/jupyterlab/pull/11238) ([@blink1073](https://github.com/blink1073)) @@ -1252,14 +2414,14 @@ No merged PRs - Use disableDocumentWideUndoRedo instead of enableDocumentWideUndoRedo [#11215](https://github.com/jupyterlab/jupyterlab/pull/11215) ([@echarles](https://github.com/echarles)) - Fix kernelspec logo handling (#11175) [#11183](https://github.com/jupyterlab/jupyterlab/pull/11183) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements -- Fix typo in docs: `page_config.json` \[#11152\]https://github.com/jupyterlab/jupyterlab/pull/11152) ([@achimgaedke](https://github.com/achimgaedke)) +- Fix typo in docs: `page_config.json` [#11152](https://github.com/jupyterlab/jupyterlab/pull/11152) ([@achimgaedke](https://github.com/achimgaedke)) - Add a menu entry to show/hide hidden files in the filebrowser [#11206](https://github.com/jupyterlab/jupyterlab/pull/11206) ([@loichuder](https://github.com/loichuder)) - Fix the "Edit on GitHub" link [#11149](https://github.com/jupyterlab/jupyterlab/pull/11149) ([@krassowski](https://github.com/krassowski)) - Clarify sidebar switching settings [#11270](https://github.com/jupyterlab/jupyterlab/pull/11270) ([@joelostblom](https://github.com/joelostblom)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-01&to=2021-10-14&type=c)) @@ -1267,57 +2429,57 @@ No merged PRs ## v3.1 -### 3.1.19 +## 3.1.19 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.18...90ed111b152665357b069cf4a42590fe07d630e8)) -#### Bugs fixed +### Bugs fixed - Added handling of '\\r' ended files [#11310](https://github.com/jupyterlab/jupyterlab/pull/11310) ([@lucabarcelos](https://github.com/lucabarcelos)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Pass version spec as an input [#11322](https://github.com/jupyterlab/jupyterlab/pull/11322) ([@jtpio](https://github.com/jtpio)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-10-07&to=2022-01-12&type=c)) [@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2021-10-07..2022-01-12&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2021-10-07..2022-01-12&type=Issues) | [@baggiponte](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abaggiponte+updated%3A2021-10-07..2022-01-12&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-10-07..2022-01-12&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-10-07..2022-01-12&type=Issues) | [@Carreau](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ACarreau+updated%3A2021-10-07..2022-01-12&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-10-07..2022-01-12&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-10-07..2022-01-12&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-10-07..2022-01-12&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-10-07..2022-01-12&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-10-07..2022-01-12&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-10-07..2022-01-12&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-10-07..2022-01-12&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-10-07..2022-01-12&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-10-07..2022-01-12&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-10-07..2022-01-12&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2021-10-07..2022-01-12&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-10-07..2022-01-12&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-10-07..2022-01-12&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-10-07..2022-01-12&type=Issues) | [@JasonWeill](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJasonWeill+updated%3A2021-10-07..2022-01-12&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-10-07..2022-01-12&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-10-07..2022-01-12&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-10-07..2022-01-12&type=Issues) | [@schmidi314](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aschmidi314+updated%3A2021-10-07..2022-01-12&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-10-07..2022-01-12&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2021-10-07..2022-01-12&type=Issues) | [@thesinepainter](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Athesinepainter+updated%3A2021-10-07..2022-01-12&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-10-07..2022-01-12&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-10-07..2022-01-12&type=Issues) | [@williamstein](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awilliamstein+updated%3A2021-10-07..2022-01-12&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2021-10-07..2022-01-12&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AZsailer+updated%3A2021-10-07..2022-01-12&type=Issues) -### 3.1.18 +## 3.1.18 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.17...c6dc40f16ea6fd1b5a58167dec6ed066de3304a9)) -#### Bugs fixed +### Bugs fixed - Backport PR #11249 on branch 3.1.x (Fix Webpack crypto handling) [#11252](https://github.com/jupyterlab/jupyterlab/pull/11252) ([@blink1073](https://github.com/blink1073)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-10-05&to=2021-10-07&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-10-05..2021-10-07&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-10-05..2021-10-07&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-10-05..2021-10-07&type=Issues) -### 3.1.17 +## 3.1.17 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.16...a899a8b9da2216d91a2426c4956bc2e711a93ecd)) -#### Bugs fixed +### Bugs fixed - Use standard hash type in webpack build [#11234](https://github.com/jupyterlab/jupyterlab/pull/11234) ([@blink1073](https://github.com/blink1073)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-10-05&to=2021-10-05&type=c)) [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-10-05..2021-10-05&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-10-05..2021-10-05&type=Issues) -### 3.1.16 +## 3.1.16 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.14...fc00631f2088d90655b0e09a96f14da86a02f911)) -#### Bugs fixed +### Bugs fixed - Do not continuously `cd('/')` when already in / [#11219](https://github.com/jupyterlab/jupyterlab/pull/11219) ([@minrk](https://github.com/minrk)) - Properly reset layout when toggling simple mode. [#11203](https://github.com/jupyterlab/jupyterlab/pull/11203) ([@jasongrout](https://github.com/jasongrout)) @@ -1325,115 +2487,115 @@ No merged PRs - Restore workspace and open tree path [#11177](https://github.com/jupyterlab/jupyterlab/pull/11177) ([@blink1073](https://github.com/blink1073)) - Share notebook's metadata [#11064](https://github.com/jupyterlab/jupyterlab/pull/11064) ([@hbcarlos](https://github.com/hbcarlos)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Check `i18n` will pass on zeroed patch pre-release version [#11214](https://github.com/jupyterlab/jupyterlab/pull/11214) ([@fcollonval](https://github.com/fcollonval)) - Fix Release Check [#11218](https://github.com/jupyterlab/jupyterlab/pull/11218) ([@fcollonval](https://github.com/fcollonval)) - Handle case when JupyterHub returns 424 for not running server [#11205](https://github.com/jupyterlab/jupyterlab/pull/11205) ([@yuvipanda](https://github.com/yuvipanda)) - Use only context and id to check `i18n` [#11190](https://github.com/jupyterlab/jupyterlab/pull/11190) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-27&to=2021-10-05&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-27..2021-10-05&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-09-27..2021-10-05&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-09-27..2021-10-05&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-09-27..2021-10-05&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-27..2021-10-05&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-09-27..2021-10-05&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-09-27..2021-10-05&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-09-27..2021-10-05&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-09-27..2021-10-05&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-27..2021-10-05&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-27..2021-10-05&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-27..2021-10-05&type=Issues) | [@loichuder](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aloichuder+updated%3A2021-09-27..2021-10-05&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-09-27..2021-10-05&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-09-27..2021-10-05&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-09-27..2021-10-05&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-09-27..2021-10-05&type=Issues) -### 3.1.15 +## 3.1.15 (Skipped due to errors in release process) -### 3.1.14 +## 3.1.14 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.13...fb6df989b70ce096c9769fc728bb158f311b48a9)) -#### Bugs fixed +### Bugs fixed - Normalize notebook cell line endings to \\n [#11141](https://github.com/jupyterlab/jupyterlab/pull/11141) ([@jasongrout](https://github.com/jasongrout)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Fix the "Edit on GitHub" link [#11149](https://github.com/jupyterlab/jupyterlab/pull/11149) ([@krassowski](https://github.com/krassowski)) -#### Documentation improvements +### Documentation improvements - Fix the "Edit on GitHub" link [#11149](https://github.com/jupyterlab/jupyterlab/pull/11149) ([@krassowski](https://github.com/krassowski)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-22&to=2021-09-27&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-22..2021-09-27&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-09-22..2021-09-27&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-22..2021-09-27&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-09-22..2021-09-27&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-09-22..2021-09-27&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-22..2021-09-27&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-22..2021-09-27&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-09-22..2021-09-27&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-09-22..2021-09-27&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-09-22..2021-09-27&type=Issues) -### 3.1.13 +## 3.1.13 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.12...a8d8f3dbceb9c852e6196b0ebd368759232e2626)) -#### Enhancements made +### Enhancements made - Fetch translations via the `ServerConnection.ISettings` [#11091](https://github.com/jupyterlab/jupyterlab/pull/11091) ([@jtpio](https://github.com/jtpio)) -#### Bugs fixed +### Bugs fixed - Update the lock after every request [#11092](https://github.com/jupyterlab/jupyterlab/pull/11092) ([@hbcarlos](https://github.com/hbcarlos)) - use posix explicitly for PathExt [#11099](https://github.com/jupyterlab/jupyterlab/pull/11099) ([@mbektas](https://github.com/mbektas)) - Backport PR #10868 on branch 3.1.x (Fix user preferences not being considered for Text Editor) [#11087](https://github.com/jupyterlab/jupyterlab/pull/11087) ([@Mithil467](https://github.com/Mithil467)) - Indent comments (#6957) [#11063](https://github.com/jupyterlab/jupyterlab/pull/11063) ([@josephrocca](https://github.com/josephrocca)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Check changes on translatable strings [#11036](https://github.com/jupyterlab/jupyterlab/pull/11036) ([@fcollonval](https://github.com/fcollonval)) - Skip flaky debugger test [#11083](https://github.com/jupyterlab/jupyterlab/pull/11083) ([@fcollonval](https://github.com/fcollonval)) -#### Documentation improvements +### Documentation improvements - Add a note on the Jupyter Releaser in the extension tutorial [#11085](https://github.com/jupyterlab/jupyterlab/pull/11085) ([@jtpio](https://github.com/jtpio)) -#### Other merged PRs +### Other merged PRs - Remove item from changelog that slips through [#11110](https://github.com/jupyterlab/jupyterlab/pull/11110) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-14&to=2021-09-22&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-14..2021-09-22&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-09-14..2021-09-22&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-14..2021-09-22&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-09-14..2021-09-22&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-14..2021-09-22&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-14..2021-09-22&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-14..2021-09-22&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-09-14..2021-09-22&type=Issues) | [@Mithil467](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AMithil467+updated%3A2021-09-14..2021-09-22&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-09-14..2021-09-22&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-09-14..2021-09-22&type=Issues) -### 3.1.12 +## 3.1.12 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.11...1af92c9bbae0eab61938bbbba0ae8cc5e9b59fdd)) -#### Bugs fixed +### Bugs fixed - Retain the rtc lock until the user releases it [#11026](https://github.com/jupyterlab/jupyterlab/pull/11026) ([@hbcarlos](https://github.com/hbcarlos)) - Backport PR #11031 on branch 3.1.x (Use posix paths explicitly) [#11045](https://github.com/jupyterlab/jupyterlab/pull/11045) ([@Mithil467](https://github.com/Mithil467)) - Adds the variable reference to the key of the component [#11029](https://github.com/jupyterlab/jupyterlab/pull/11029) ([@hbcarlos](https://github.com/hbcarlos)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Clean up bumpversion [#11056](https://github.com/jupyterlab/jupyterlab/pull/11056) ([@blink1073](https://github.com/blink1073)) - Make debugger jest test more robust [#11032](https://github.com/jupyterlab/jupyterlab/pull/11032) ([@fcollonval](https://github.com/fcollonval)) -#### Documentation improvements +### Documentation improvements - Added Table of contents (toc.rst) to user guide documentation [#10699](https://github.com/jupyterlab/jupyterlab/pull/10699) ([@AnudeepGunukula](https://github.com/AnudeepGunukula)) -#### Other merged PRs +### Other merged PRs - Remove status bar item flickering [#11065](https://github.com/jupyterlab/jupyterlab/pull/11065) ([@fcollonval](https://github.com/fcollonval)) - Backport PR #10954 on branch 3.1.x (Improve release notes for 3.1) [#11053](https://github.com/jupyterlab/jupyterlab/pull/11053) ([@Mithil467](https://github.com/Mithil467)) - use path.posix explicitly for URLs [#11048](https://github.com/jupyterlab/jupyterlab/pull/11048) ([@mbektas](https://github.com/mbektas)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-08&to=2021-09-14&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-08..2021-09-14&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-08..2021-09-14&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-09-08..2021-09-14&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-09-08..2021-09-14&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-08..2021-09-14&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-08..2021-09-14&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-08..2021-09-14&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-09-08..2021-09-14&type=Issues) | [@Mithil467](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AMithil467+updated%3A2021-09-08..2021-09-14&type=Issues) -### 3.1.11 +## 3.1.11 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.10...f04391135c11c6c5e3e8c4706ec26e675f0db4d6)) -#### Bugs fixed +### Bugs fixed - Revert pending input PR #10792 merged in 3.1.x branch [#11020](https://github.com/jupyterlab/jupyterlab/pull/11020) ([@echarles](https://github.com/echarles)) - fix #10997 - increase max_message_size of websocket messages [#11003](https://github.com/jupyterlab/jupyterlab/pull/11003) ([@dmonad](https://github.com/dmonad)) @@ -1443,74 +2605,74 @@ No merged PRs - Backport PR #10943 on branch 3.1.x (Simplify IRankedMenu interface) [#10991](https://github.com/jupyterlab/jupyterlab/pull/10991) ([@fcollonval](https://github.com/fcollonval)) - Add a guard to avoid kernel deadlock on multiple input request [#10792](https://github.com/jupyterlab/jupyterlab/pull/10792) ([@echarles](https://github.com/echarles)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Clean up handling of npm dist tag [#10999](https://github.com/jupyterlab/jupyterlab/pull/10999) ([@fcollonval](https://github.com/fcollonval)) - Fix version regex [#10994](https://github.com/jupyterlab/jupyterlab/pull/10994) ([@fcollonval](https://github.com/fcollonval)) -#### Documentation improvements +### Documentation improvements - Update documentation for internationalization [#11024](https://github.com/jupyterlab/jupyterlab/pull/11024) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-01&to=2021-09-08&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-01..2021-09-08&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-09-01..2021-09-08&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-09-01..2021-09-08&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-09-01..2021-09-08&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-01..2021-09-08&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-09-01..2021-09-08&type=Issues) -### 3.1.10 +## 3.1.10 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.9...646b708cdb76f6d0e4e622b0546cc4dc7d2854c7)) -#### Bugs fixed +### Bugs fixed - Add "menu" context for translation of menu labels [#10932](https://github.com/jupyterlab/jupyterlab/pull/10932) ([@krassowski](https://github.com/krassowski)) - Fix lack of translation of part of "Saving completed" and friends [#10958](https://github.com/jupyterlab/jupyterlab/pull/10958) ([@krassowski](https://github.com/krassowski)) - Add undoManager to inserted cells [#10899](https://github.com/jupyterlab/jupyterlab/pull/10899) ([@hbcarlos](https://github.com/hbcarlos)) - Render placeholder at correct index [#10898](https://github.com/jupyterlab/jupyterlab/pull/10898) ([@echarles](https://github.com/echarles)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Backport PR #10983 on branch 3.1.x (Update to lerna 4) [#10985](https://github.com/jupyterlab/jupyterlab/pull/10985) ([@blink1073](https://github.com/blink1073)) - Clarify usage of mock in debugger test [#10979](https://github.com/jupyterlab/jupyterlab/pull/10979) ([@fcollonval](https://github.com/fcollonval)) - Restore test for kernel that does not support debugger [#10973](https://github.com/jupyterlab/jupyterlab/pull/10973) ([@fcollonval](https://github.com/fcollonval)) - Backport PR #10937: More Publish Integrity [#10938](https://github.com/jupyterlab/jupyterlab/pull/10938) ([@blink1073](https://github.com/blink1073)) -#### Documentation improvements +### Documentation improvements - Backport #10893 on branch 3.1.x (Add internationalization documentation) [#10974](https://github.com/jupyterlab/jupyterlab/pull/10974) ([@fcollonval](https://github.com/fcollonval)) - Fix formatting of a link in the changelog [#10945](https://github.com/jupyterlab/jupyterlab/pull/10945) ([@jtpio](https://github.com/jtpio)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-08-25&to=2021-09-01&type=c)) [@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2021-08-25..2021-09-01&type=Issues) | [@baggiponte](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abaggiponte+updated%3A2021-08-25..2021-09-01&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-08-25..2021-09-01&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-08-25..2021-09-01&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-08-25..2021-09-01&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-08-25..2021-09-01&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-08-25..2021-09-01&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-08-25..2021-09-01&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-08-25..2021-09-01&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-08-25..2021-09-01&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-08-25..2021-09-01&type=Issues) | [@mbektas](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ambektas+updated%3A2021-08-25..2021-09-01&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-08-25..2021-09-01&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-08-25..2021-09-01&type=Issues) | [@SarunasAzna](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASarunasAzna+updated%3A2021-08-25..2021-09-01&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-08-25..2021-09-01&type=Issues) -### 3.1.9 +## 3.1.9 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.8...8f8cfc548c7c91e9dcf0dc51fd6eafc98f3fcfef)) -#### Bugs fixed +### Bugs fixed - Fix Package Publish [#10916](https://github.com/jupyterlab/jupyterlab/pull/10916) ([@afshin](https://github.com/afshin)) - Remove terminal theme menu if terminal feature is disabled [#10909](https://github.com/jupyterlab/jupyterlab/pull/10909) ([@Mithil467](https://github.com/Mithil467)) -#### Documentation improvements +### Documentation improvements - Correct the documentation for packaging [#10910](https://github.com/jupyterlab/jupyterlab/pull/10910) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-08-24&to=2021-08-25&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-08-24..2021-08-25&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-08-24..2021-08-25&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-08-24..2021-08-25&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-08-24..2021-08-25&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-08-24..2021-08-25&type=Issues) -### 3.1.8 +## 3.1.8 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.7...ecb8be24857466a69e4643a5a708b29a062d8465)) -#### Bugs fixed +### Bugs fixed - Workaround invasive use of tex mode inside of code elements and blocks [#10867](https://github.com/jupyterlab/jupyterlab/pull/10867) ([@krassowski](https://github.com/krassowski)) - Keep cursor at the previous position after cell split [#10884](https://github.com/jupyterlab/jupyterlab/pull/10884) ([@krassowski](https://github.com/krassowski)) @@ -1522,147 +2684,147 @@ No merged PRs - Get metadata from shared model when serializing the notebook to JSON [#10804](https://github.com/jupyterlab/jupyterlab/pull/10804) ([@hbcarlos](https://github.com/hbcarlos)) - Shutdown sessions/terminals on shutdown [#10843](https://github.com/jupyterlab/jupyterlab/pull/10843) ([@martinRenou](https://github.com/martinRenou)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Backport PR #10891 on branch 3.1.x (Publish Cleanup) [#10897](https://github.com/jupyterlab/jupyterlab/pull/10897) ([@fcollonval](https://github.com/fcollonval)) - Fix Publish Check [#10846](https://github.com/jupyterlab/jupyterlab/pull/10846) ([@afshin](https://github.com/afshin)) - Translate labels of menus and submenus [#10739](https://github.com/jupyterlab/jupyterlab/pull/10739) ([@krassowski](https://github.com/krassowski)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-08-16&to=2021-08-24&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-08-16..2021-08-24&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-08-16..2021-08-24&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-08-16..2021-08-24&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-08-16..2021-08-24&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-08-16..2021-08-24&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-08-16..2021-08-24&type=Issues) -### 3.1.7 +## 3.1.7 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.6...e0a6d74212394a40ba00a12d8043f1b49326f73d)) -#### Bugs fixed +### Bugs fixed - Fix link to the security documentation [#10836](https://github.com/jupyterlab/jupyterlab/pull/10836) ([@krassowski](https://github.com/krassowski)) - The dirty indicator does not get cleared up after reverting changes [#10812](https://github.com/jupyterlab/jupyterlab/pull/10812) ([@fcollonval](https://github.com/fcollonval)) - Remove session error dialog redundant error message to avoid repeated display [#10810](https://github.com/jupyterlab/jupyterlab/pull/10810) ([@franckchen](https://github.com/franckchen)) - Use nullish operator instead of OR [#10811](https://github.com/jupyterlab/jupyterlab/pull/10811) ([@fcollonval](https://github.com/fcollonval)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Remove outdated `npm-cli-login` utility from buildutils [#10828](https://github.com/jupyterlab/jupyterlab/pull/10828) ([@krassowski](https://github.com/krassowski)) - More Releaser Fixes [#10817](https://github.com/jupyterlab/jupyterlab/pull/10817) ([@afshin](https://github.com/afshin)) -#### Documentation improvements +### Documentation improvements - Fix documentation snippets [#10813](https://github.com/jupyterlab/jupyterlab/pull/10813) ([@fcollonval](https://github.com/fcollonval)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-08-12&to=2021-08-16&type=c)) [@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-08-12..2021-08-16&type=Issues) | [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-08-12..2021-08-16&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-08-12..2021-08-16&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-08-12..2021-08-16&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-08-12..2021-08-16&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-08-12..2021-08-16&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-08-12..2021-08-16&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-08-12..2021-08-16&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-08-12..2021-08-16&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-08-12..2021-08-16&type=Issues) -### 3.1.6 +## 3.1.6 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.5...4cec12eba17eaf313241b595e98b40cb0a851e65)) -#### Bugs fixed +### Bugs fixed - Backport PR #10738 on branch 3.1.x [#10806](https://github.com/jupyterlab/jupyterlab/pull/10806) ([@krassowski](https://github.com/krassowski)) - Share nbformat and nbformatMinor [#10795](https://github.com/jupyterlab/jupyterlab/pull/10795) ([@hbcarlos](https://github.com/hbcarlos)) - Support collapsible headers with virtual notebook rendering [#10793](https://github.com/jupyterlab/jupyterlab/pull/10793) ([@echarles](https://github.com/echarles)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Clean up Link Caching Again [#10794](https://github.com/jupyterlab/jupyterlab/pull/10794) ([@afshin](https://github.com/afshin)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-08-09&to=2021-08-12&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-08-09..2021-08-12&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-08-09..2021-08-12&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-08-09..2021-08-12&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-08-09..2021-08-12&type=Issues) -### 3.1.5 +## 3.1.5 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.4...6d14f7f8d3a7400a5fddbbdfaf79d0b8bdd5325f)) -#### Bugs fixed +### Bugs fixed - Revert input guard [#10779](https://github.com/jupyterlab/jupyterlab/pull/10779) ([@echarles](https://github.com/echarles)) - Markdown url resolver no longer throws for malformed URLs in `isLocal` check [#10773](https://github.com/jupyterlab/jupyterlab/pull/10773) ([@loichuder](https://github.com/loichuder)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-08-05&to=2021-08-09&type=c)) [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-08-05..2021-08-09&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-08-05..2021-08-09&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-08-05..2021-08-09&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-08-05..2021-08-09&type=Issues) -### 3.1.2 +## 3.1.2 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.1...be8032d1a932e09f553d0343659e89a6a25a516f)) -#### Enhancements made +### Enhancements made - Normalize translation domain [#10728](https://github.com/jupyterlab/jupyterlab/pull/10728) ([@fcollonval](https://github.com/fcollonval)) -#### Bugs fixed +### Bugs fixed - Prevent undo/redo in outputs [#10756](https://github.com/jupyterlab/jupyterlab/pull/10756) ([@hbcarlos](https://github.com/hbcarlos)) - Revert change in saveState Signal [#10741](https://github.com/jupyterlab/jupyterlab/pull/10741) ([@jess-x](https://github.com/jess-x)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Another Fix to Verdaccio Publishing [#10747](https://github.com/jupyterlab/jupyterlab/pull/10747) ([@afshin](https://github.com/afshin)) - More Cleanup of Automated Release Process [#10742](https://github.com/jupyterlab/jupyterlab/pull/10742) ([@blink1073](https://github.com/blink1073)) - Fix Verdaccio Publish [#10743](https://github.com/jupyterlab/jupyterlab/pull/10743) ([@afshin](https://github.com/afshin)) - Yet another fix for Verdaccio publish [#10759](https://github.com/jupyterlab/jupyterlab/pull/10759) ([@afshin](https://github.com/afshin)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-07-29&to=2021-08-04&type=c)) [@AnudeepGunukula](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AAnudeepGunukula+updated%3A2021-07-29..2021-08-04&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-07-29..2021-08-04&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-07-29..2021-08-04&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-07-29..2021-08-04&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-07-29..2021-08-04&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-07-29..2021-08-04&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-07-29..2021-08-04&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-07-29..2021-08-04&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-07-29..2021-08-04&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-07-29..2021-08-04&type=Issues) -### 3.1.1 +## 3.1.1 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.0...6b09ac27dcde158a2dee9df1499af384fce7086a)) -#### Bugs fixed +### Bugs fixed - Use appName in page title when restoring workspaces (vs 3.1.x) [#10724](https://github.com/jupyterlab/jupyterlab/pull/10724) ([@bollwyvl](https://github.com/bollwyvl)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Add branch integrity handling [#10708](https://github.com/jupyterlab/jupyterlab/pull/10708) ([@afshin](https://github.com/afshin)) -#### Documentation improvements +### Documentation improvements - Add branch integrity handling [#10708](https://github.com/jupyterlab/jupyterlab/pull/10708) ([@afshin](https://github.com/afshin)) - Minor improvement to contributing documentation [#10713](https://github.com/jupyterlab/jupyterlab/pull/10713) ([@KrishnaKumarHariprasannan](https://github.com/KrishnaKumarHariprasannan)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-07-27&to=2021-07-29&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-07-27..2021-07-29&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-07-27..2021-07-29&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-07-27..2021-07-29&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-07-27..2021-07-29&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-07-27..2021-07-29&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-07-27..2021-07-29&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-07-27..2021-07-29&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-07-27..2021-07-29&type=Issues) -### 3.1.0 +## 3.1.0 ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.0.6...60f37be54a714c391fad5500cb57055af1492591)) -#### User-facing changes +### User-facing changes - From JupyterLab 3.1, file documents and notebooks have collaborative editing using the [Yjs shared editing framework](https://github.com/yjs/yjs). Editors are not collaborative by default; to activate it, start JupyterLab - with the `--collaborative` flag. See full documentation on [collaboration](https://jupyterlab.readthedocs.io/en/3.6.x/user/rtc.html). + with the `--collaborative` flag. See full documentation on [collaboration](https://jupyterlab.readthedocs.io/en/stable/user/rtc.html). - The undo/redo history in the notebook is now document-wide (tracking changes across all cells); the future verisions will enable restoring the previous behaviour of per-cell undo/redo. -- Table of Contents recieved multiple new features and settings described in the [user documentation](https://jupyterlab.readthedocs.io/en/3.6.x/user/toc.html). +- Table of Contents recieved multiple new features and settings described in the [user documentation](https://jupyterlab.readthedocs.io/en/stable/user/toc.html). - The debugger recived many improvements, including basic support for evaluating code at a breakpoint, and for variable inspection. - The closing bracket is no longer automatically added by default; the old behaviour can be re-enabled from the menu bar (`Settings` -> `Auto Close Brackets`) or from the Advanced Settings Editor. - A new visual indicator was introduced to highlight cells in which the code changed in the editor since last execution: A GIF of the visual indicator showing up after editing a cell. - Many other new features were added as documented below. -#### New features added +### New features added - General: Shared editing with collaborative notebook model. [#10118](https://github.com/jupyterlab/jupyterlab/pull/10118) ([@dmonad](https://github.com/dmonad)) - Debugger: Implemented variable inspection when the debugger has started [#10025](https://github.com/jupyterlab/jupyterlab/pull/10025) ([@JohanMabille](https://github.com/JohanMabille)) @@ -1681,7 +2843,7 @@ No merged PRs - Customization: Add `cursorBlinkRate` settings for editors [#10485](https://github.com/jupyterlab/jupyterlab/pull/10485) ([@fcollonval](https://github.com/fcollonval)) - Licenses: Add a list of licenses accessible from the UI [#9779](https://github.com/jupyterlab/jupyterlab/pull/9779) ([@bollwyvl](https://github.com/bollwyvl)) -#### Enhancements made +### Enhancements made - Add license-webpack-plugin [#9519](https://github.com/jupyterlab/jupyterlab/pull/9519) ([@bollwyvl](https://github.com/bollwyvl)) - Focus cells on split and leave cursor in cell with selection when splitting [#10297](https://github.com/jupyterlab/jupyterlab/pull/10297) ([@goanpeca](https://github.com/goanpeca)) @@ -1750,7 +2912,7 @@ No merged PRs - Search installed extensions [#7423](https://github.com/jupyterlab/jupyterlab/pull/7423) ([@jtpio](https://github.com/jtpio)) - Add "go-up" navigation support in filebrowser, fix other shortcuts behaviour [#6859](https://github.com/jupyterlab/jupyterlab/pull/6859) ([@krassowski](https://github.com/krassowski)) -#### Bugs fixed +### Bugs fixed - Workaround disappearing palette issue by using blur [#10693](https://github.com/jupyterlab/jupyterlab/pull/10693) ([@krassowski](https://github.com/krassowski)) - Set anonymous username bug [#10686](https://github.com/jupyterlab/jupyterlab/pull/10686) ([@hbcarlos](https://github.com/hbcarlos)) @@ -1777,7 +2939,7 @@ No merged PRs - Fix contrast issues in command palette and file browser [#10531](https://github.com/jupyterlab/jupyterlab/pull/10531) ([@krassowski](https://github.com/krassowski)) - fix running cell when focused on output [#10517](https://github.com/jupyterlab/jupyterlab/pull/10517) ([@cameron-toy](https://github.com/cameron-toy)) - Check to make sure process.argv exists before using it. [#10507](https://github.com/jupyterlab/jupyterlab/pull/10507) ([@jasongrout](https://github.com/jasongrout)) -- \[HOTFIX\] Render the correct index placeholder cell [#10505](https://github.com/jupyterlab/jupyterlab/pull/10505) ([@echarles](https://github.com/echarles)) +- \[HOTFIX\] Render the correct index placeholder cell [#10505](https://github.com/jupyterlab/jupyterlab/pull/10505) ([@echarles](https://github.com/echarles)) - Remove content-visibility css prop to avoid jumpy scrollbar [#10503](https://github.com/jupyterlab/jupyterlab/pull/10503) ([@echarles](https://github.com/echarles)) - Fix checkbox styling [#10483](https://github.com/jupyterlab/jupyterlab/pull/10483) ([@fcollonval](https://github.com/fcollonval)) - Fix icons code for TOC and listings-info [#10476](https://github.com/jupyterlab/jupyterlab/pull/10476) ([@krassowski](https://github.com/krassowski)) @@ -1838,7 +3000,7 @@ No merged PRs - Use Path.resolve() to get canonical case-sensitive path names [#9709](https://github.com/jupyterlab/jupyterlab/pull/9709) ([@jasongrout](https://github.com/jasongrout)) - Fix use of hyphen in module name [#9655](https://github.com/jupyterlab/jupyterlab/pull/9655) ([@hbcarlos](https://github.com/hbcarlos)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Clean up Link Caching [#10687](https://github.com/jupyterlab/jupyterlab/pull/10687) ([@afshin](https://github.com/afshin)) - Clean up link checking [#10673](https://github.com/jupyterlab/jupyterlab/pull/10673) ([@blink1073](https://github.com/blink1073)) @@ -1978,7 +3140,7 @@ No merged PRs - Make the filebrowser plugins more reusable [#9667](https://github.com/jupyterlab/jupyterlab/pull/9667) ([@jtpio](https://github.com/jtpio)) - fix: use process/browser module as real polyfill [#9636](https://github.com/jupyterlab/jupyterlab/pull/9636) ([@maartenbreddels](https://github.com/maartenbreddels)) -#### Documentation improvements +### Documentation improvements - Add alt attirbutes for test docs sprint [#10670](https://github.com/jupyterlab/jupyterlab/pull/10670) ([@isabela-pf](https://github.com/isabela-pf)) - Add some upgrade notes to JupyterLab 3.1 [#10654](https://github.com/jupyterlab/jupyterlab/pull/10654) ([@fcollonval](https://github.com/fcollonval)) @@ -2039,7 +3201,7 @@ No merged PRs - Update notebook toolbar example docs [#9705](https://github.com/jupyterlab/jupyterlab/pull/9705) ([@blink1073](https://github.com/blink1073)) - DOC: Make code block background less ugly [#9413](https://github.com/jupyterlab/jupyterlab/pull/9413) ([@mgeier](https://github.com/mgeier)) -#### Contributors to this release +### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-01-28&to=2021-07-27&type=c)) @@ -2056,7 +3218,7 @@ closed. ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.0.15...2badf555436063962451599a81b38b80f601a589)) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - Fix Shutdown Error in Test App [#10240](https://github.com/jupyterlab/jupyterlab/pull/10240) ([@afshin](https://github.com/afshin)) - Update to `codemirror~=5.58.0` [#10262](https://github.com/jupyterlab/jupyterlab/pull/10262) ([@jtpio](https://github.com/jtpio)) @@ -2065,20 +3227,20 @@ closed. ([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.0.14...e1cda8e2fb69a6a01ec261ce13413acd306df4cb)) -#### Enhancements made +### Enhancements made - Added support for namespace packages in labextensions. [#10150](https://github.com/jupyterlab/jupyterlab/pull/10150) [@mellesies](https://github.com/mellesies) -#### Maintenance and upkeep improvements +### Maintenance and upkeep improvements - \[3.0.x\] Remove Dependency on Jupyter Packaging [#10218](https://github.com/jupyterlab/jupyterlab/pull/10218) ([@jtpio](https://github.com/jtpio)) -#### Documentation improvements +### Documentation improvements - \[3.0.x\] Fix changelong entries for 3.0.13 [#10087](https://github.com/jupyterlab/jupyterlab/pull/10087) ([@blink1073](https://github.com/blink1073)) - chore: update extension_tutorial [#10026](https://github.com/jupyterlab/jupyterlab/pull/10026) [@0618](https://github.com/0618) -#### Other merged PRs +### Other merged PRs - Workaround Chromium issue with iframe reload/href [#10185](https://github.com/jupyterlab/jupyterlab/pull/10185) [@krassowski](https://github.com/krassowski) - Update to `sanitize-html~=2.3.3` [#10220](https://github.com/jupyterlab/jupyterlab/pull/10220) [@jtpio](https://github.com/jtpio) @@ -2266,9 +3428,9 @@ closed. ### v3.0.0 -#### User-facing changes +### User-facing changes -##### Extensions can be installed without building JupyterLab with NodeJS +#### Extensions can be installed without building JupyterLab with NodeJS In JupyterLab 3.0, a new recommended way of distributing and installing extensions as Python pip or conda packages is available. Installing such @@ -2276,30 +3438,30 @@ extensions does not require rebuilding JupyterLab and does not require having NodeJS installed. The previous way of distributing extensions as npm packages requiring rebuilding JupyterLab is still available as well. See the -[documentation](https://jupyterlab.readthedocs.io/en/3.6.x/user/extensions.html#extensions) +[documentation](https://jupyterlab.readthedocs.io/en/stable/user/extensions.html#extensions) for more details. -##### The JupyterLab interface supports multiple languages +#### The JupyterLab interface supports multiple languages JupyterLab now provides the ability to set the display language of the user interface. See the -[documentation](https://jupyterlab.readthedocs.io/en/3.6.x/user/language.html) +[documentation](https://jupyterlab.readthedocs.io/en/stable/user/language.html) for more details. -##### A new visual debugger +#### A new visual debugger JupyterLab now ships with a debugger front-end by default, available for kernels that support the new debugging protocol. See the -[documentation](https://jupyterlab.readthedocs.io/en/3.6.x/user/debugger.html) +[documentation](https://jupyterlab.readthedocs.io/en/stable/user/debugger.html) for more details. -##### Improvements to Simple Interface mode and Mobile +#### Improvements to Simple Interface mode and Mobile The Simple Interface mode (previously Single Document Mode) is now more streamlined. JupyterLab now supports showing the current file in use in the browser URL bar, similar to the classic Jupyter Notebook. -##### Table of Contents is now in core +#### Table of Contents is now in core The popular Table of Contents extension is now part of core JupyterLab. This core extension makes it easy to see an outline view of notebooks @@ -2310,7 +3472,7 @@ and other documents. The file browser now has a filter input which filters the list of files using the same fuzzy matching as the command palette. -##### Property inspector moved to right sidebar +#### Property inspector moved to right sidebar The default interface for JupyterLab now has system-wide sidebar panes on the left side and sidebar panels that interact with a specific @@ -2319,7 +3481,7 @@ right side. As always, you can move panes between the left and right sidebars (right click on the sidebar icon, or change it in Advanced Settings). -##### Command Palette +#### Command Palette The command palette is now a floating window that appears on top of your JupyterLab workspace. This enables users to quickly invoke a command @@ -2336,9 +3498,9 @@ the [Migration Guide](https://jupyter-server.readthedocs.io/en/stable/operators/migrate-from-nbserver.html) to migrate custom notebook configuration to Jupyter Server. -#### For Developers +### For Developers -##### Prebuilt Extensions +#### Prebuilt Extensions Users will typically consume prebuilt extensions, which are Python packages with static assets built using `JupyterLab`. See the updated @@ -2584,7 +3746,7 @@ update extensions to use - Jupyterlab as server extension ([#7416](https://github.com/jupyterlab/jupyterlab/pull/7416)) -##### Internationalization +#### Internationalization The JupyterLab UI now supports translation. @@ -2631,7 +3793,7 @@ The JupyterLab UI now supports translation. ([#8747](https://github.com/jupyterlab/jupyterlab/pull/8747), [#75](https://github.com/jupyterlab/team-compass/issues/75)) -##### Table of Contents +#### Table of Contents - Update toc ui ([#9275](https://github.com/jupyterlab/jupyterlab/pull/9275)) @@ -2649,7 +3811,7 @@ The JupyterLab UI now supports translation. - Merge toc extension into core ([#8538](https://github.com/jupyterlab/jupyterlab/pull/8538)) -##### Other +#### Other - Resolve 'restarting' state on reconnect ([#9484](https://github.com/jupyterlab/jupyterlab/pull/9484), @@ -2932,7 +4094,7 @@ The JupyterLab UI now supports translation. - Add a debugger section to the user docs and contributing guide ([#8977](https://github.com/jupyterlab/jupyterlab/pull/8977)) -##### Single Document Mode and Mobile Enhancements +#### Single Document Mode and Mobile Enhancements - Make the single document title widget work for widgets that are not main area widgets @@ -2957,7 +4119,7 @@ The JupyterLab UI now supports translation. - Incrementally improve jupyterlab mobile ux ([#8456](https://github.com/jupyterlab/jupyterlab/pull/8456)) -##### Benchmarks (now a separate repository) +#### Benchmarks (now a separate repository) - Move benchmarks to seperate repo ([#8795](https://github.com/jupyterlab/jupyterlab/pull/8795)) @@ -2973,7 +4135,7 @@ The JupyterLab UI now supports translation. - Benchmark notebook loads ([#8020](https://github.com/jupyterlab/jupyterlab/pull/8020)) -#### Bugfixes +### Bugfixes - Fix lerna warning ([#9061](https://github.com/jupyterlab/jupyterlab/pull/9061)) @@ -3066,9 +4228,9 @@ The JupyterLab UI now supports translation. - Reconnect a websocket when a kernel is restarted. ([#8432](https://github.com/jupyterlab/jupyterlab/pull/8432)) -### [v2.2.x](https://github.com/jupyterlab/jupyterlab/milestone/53) +## [v2.2.x](https://github.com/jupyterlab/jupyterlab/milestone/53) -### [v2.2.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v2.2.0) +## [v2.2.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v2.2.0) See the [JupyterLab 2.2](https://github.com/jupyterlab/jupyterlab/milestone/53?closed=1) @@ -3080,7 +4242,7 @@ closed. We are very excited to add Eric Charles to the core team this month! ([#8513](https://github.com/jupyterlab/jupyterlab/pull/8513)) -#### User-facing changes +### User-facing changes - Cells can no longer be executed while kernels are terminating or restarting. There is a new status for these events on the Kernel @@ -3127,7 +4289,7 @@ We are very excited to add Eric Charles to the core team this month! -#### For developers +### For developers - Specify that we recommend typescript over javascript for extensions ([#8411](https://github.com/jupyterlab/jupyterlab/pull/8411)) @@ -3148,7 +4310,7 @@ We are very excited to add Eric Charles to the core team this month! - Improve whitelist figure description in documentation ([#8517](https://github.com/jupyterlab/jupyterlab/pull/8517)) -#### Bugfixes +### Bugfixes - Typo: fix extensino to extension ([#8512](https://github.com/jupyterlab/jupyterlab/pull/8512)) @@ -3194,7 +4356,7 @@ We are very excited to add Eric Charles to the core team this month! ([#8593](https://github.com/jupyterlab/jupyterlab/pull/8593), [#8587](https://github.com/jupyterlab/jupyterlab/issues/8587)) -### [v2.1.x](https://github.com/jupyterlab/jupyterlab/milestone/55) +## [v2.1.x](https://github.com/jupyterlab/jupyterlab/milestone/55) ### v2.1.2 @@ -3214,16 +4376,16 @@ We are very excited to add Eric Charles to the core team this month! - Fix Save As for files without sessions ([#8248](https://github.com/jupyterlab/jupyterlab/pull/8248)) -### [v2.1.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v2.1.0) +## [v2.1.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v2.1.0) -#### April 2020 +### April 2020 See the [JupyterLab 2.1](https://github.com/jupyterlab/jupyterlab/milestone/49?closed=1) milestone on GitHub for the full list of pull requests and issues closed. -#### User-facing changes +### User-facing changes - Display the extension manager in the left sidebar by default. Users will need to acknowledge the disclaimer in the extension manager @@ -3240,7 +4402,7 @@ closed. notebook toolbar ([#8024](https://github.com/jupyterlab/jupyterlab/pull/8024)) - + - Added a context menu item for opening a Markdown editor from the Markdown preview @@ -3286,7 +4448,7 @@ closed. } ``` -#### For developers +### For developers - `NotebookWidgetFactory` is now a plugin so it can be overridden ([#8066](https://github.com/jupyterlab/jupyterlab/pull/8066), @@ -3303,7 +4465,7 @@ closed. ([#7877](https://github.com/jupyterlab/jupyterlab/pull/7877), [#7670](https://github.com/jupyterlab/jupyterlab/issues/7670)) -#### Bugfixes +### Bugfixes - Fix property inspector restoration on reload ([#8114](https://github.com/jupyterlab/jupyterlab/pull/8114)) @@ -3327,9 +4489,9 @@ closed. ([#7832](https://github.com/jupyterlab/jupyterlab/pull/7832), [#7760](https://github.com/jupyterlab/jupyterlab/pull/7760)) -### [v2.0.2](https://github.com/jupyterlab/jupyterlab/releases/tag/v2.0.2) +## [v2.0.2](https://github.com/jupyterlab/jupyterlab/releases/tag/v2.0.2) -#### April 2020 +### April 2020 See the [JupyterLab 2.0.2](https://github.com/jupyterlab/jupyterlab/milestone/50?closed=1) @@ -3349,33 +4511,33 @@ closed. not including `undefined` ([#8032](https://github.com/jupyterlab/jupyterlab/pull/8032)) -### [v2.0.0](https://github.com/jupyterlab/jupyterlab/releases) +## [v2.0.0](https://github.com/jupyterlab/jupyterlab/releases) -#### February 2020 +### February 2020 Here are some highlights for this release. See the [JupyterLab 2.0](https://github.com/jupyterlab/jupyterlab/milestone/36?closed=1) milestone on GitHub for the full list of pull requests and issues closed. -#### User-facing changes +### User-facing changes - New user interface for notebook cell tags ([#7407](https://github.com/jupyterlab/jupyterlab/pull/7407), [#7786](https://github.com/jupyterlab/jupyterlab/pull/7786)) - + - File info display when hovering on a file in the file browser ([#7485](https://github.com/jupyterlab/jupyterlab/pull/7485), [#7352](https://github.com/jupyterlab/jupyterlab/issues/7352)) - + - Support for searching outputs in notebooks ([#7258](https://github.com/jupyterlab/jupyterlab/pull/7258)) - + - `Ctrl Shift .` and `Ctrl Shift ,` shortcuts move focus to the next and previous tab bar in the main area, respectively @@ -3477,12 +4639,12 @@ closed. setting instead of the deprecated and now removed `labhubapp` ([#7724](https://github.com/jupyterlab/jupyterlab/pull/7724)) -#### For developers +### For developers See `extension_migration` for help in migrating extensions to JupyterLab 2.0. -##### Backward incompatible changes +#### Backward incompatible changes - Switch from `@phosphor` to `@lumino` dependencies. ([#7582](https://github.com/jupyterlab/jupyterlab/pull/7582), @@ -3539,7 +4701,7 @@ migrating extensions to JupyterLab 2.0. [#7864](https://github.com/jupyterlab/jupyterlab/pull/7864), [#7886](https://github.com/jupyterlab/jupyterlab/pull/7886)) -##### Other changes +#### Other changes - New property inspector used to display the properties of the currently selected main area widget @@ -3618,7 +4780,7 @@ migrating extensions to JupyterLab 2.0. - Apply all options to the initial JupyterLab application instance ([#7251](https://github.com/jupyterlab/jupyterlab/pull/7251)) -#### Bugfixes +### Bugfixes - "Copy Shareable Link" in the file browser context menu now properly works in JupyterHub @@ -3713,16 +4875,16 @@ migrating extensions to JupyterLab 2.0. ([#7268](https://github.com/jupyterlab/jupyterlab/pull/7268), [#7264](https://github.com/jupyterlab/jupyterlab/issues/7264)) -### [v1.2.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v1.2.0) +## [v1.2.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v1.2.0) -#### October 29, 2019 +### October 29, 2019 Here are some highlights for this release. See the [JupyterLab 1.2.0](https://github.com/jupyterlab/jupyterlab/milestone/38?closed=1) milestone on GitHub for the full list of pull requests and issues closed. -#### User-facing changes +### User-facing changes - Select cells from the current cell to the top of the notebook with `Shift Home`, to the bottom of the notebook with `Shift End` @@ -3756,7 +4918,7 @@ closed. [#7249](https://github.com/jupyterlab/jupyterlab/pull/7249), [#7248](https://github.com/jupyterlab/jupyterlab/issues/7248)) -#### For developers +### For developers - Update the Markdown renderer (`marked`) to 0.7.0 ([#7328](https://github.com/jupyterlab/jupyterlab/pull/7328)) @@ -3781,7 +4943,7 @@ closed. ([#6864](https://github.com/jupyterlab/jupyterlab/pull/6864), [#3320](https://github.com/jupyterlab/jupyterlab/issues/3320)) -#### Bugfixes +### Bugfixes - Fix the `file-browser-path` query parameter ([#7313](https://github.com/jupyterlab/jupyterlab/pull/7313)) @@ -3803,16 +4965,16 @@ closed. [#7417](https://github.com/jupyterlab/jupyterlab/pull/7417), [#7419](https://github.com/jupyterlab/jupyterlab/pull/7419)) -### [v1.1.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v1.1.0) +## [v1.1.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v1.1.0) -#### August 28, 2019 +### August 28, 2019 Here are some highlights of what is in this release. See the [JupyterLab 1.1.0](https://github.com/jupyterlab/jupyterlab/milestone/31?closed=1) milestone on GitHub for the full list of pull requests and issues closed. -#### User-facing changes +### User-facing changes - `jupyter lab build` now has a `--minimize=False` option to build without minimization to conserve memory and time @@ -3846,7 +5008,7 @@ closed. JupyterLab server extension. See the issue for more details ([#7042](https://github.com/jupyterlab/jupyterlab/issues/7042)) -#### For developers +### For developers - Expose install_kernel for tests so that outside projects can better use the testing framework @@ -3871,7 +5033,7 @@ closed. - Add server side coreconfig object ([#6991](https://github.com/jupyterlab/jupyterlab/pull/6991)) -#### Bug fixes +### Bug fixes - Handle errors that occur during kernel selection ([#7094](https://github.com/jupyterlab/jupyterlab/pull/7094)) @@ -3898,7 +5060,7 @@ closed. ([#6933](https://github.com/jupyterlab/jupyterlab/pull/6933), [#6935](https://github.com/jupyterlab/jupyterlab/pull/6935)) -### [v1.0.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v1.0.0) +## [v1.0.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v1.0.0) ### June 28, 2019 @@ -3907,9 +5069,9 @@ See the [JupyterLab milestone on GitHub for the full list of pull requests and issues closed in 1.0.0, and other 1.0.x milestones for bugs fixed in patch releases. -#### Find and Replace +### Find and Replace - + We have added first class support for find and replace across JupyterLab. It is currently supported in notebooks and text files and is @@ -3930,9 +5092,9 @@ extensible for other widgets who wish to support it. [#5795](https://github.com/jupyterlab/jupyterlab/pull/5795), [#1074](https://github.com/jupyterlab/jupyterlab/issues/1074)) -#### Status Bar +### Status Bar - + We have integrated the [JupyterLab Status Bar package](https://github.com/jupyterlab/jupyterlab-statusbar) package @@ -3956,14 +5118,14 @@ well ([#5577](https://github.com/jupyterlab/jupyterlab/pull/5577), ([#6087](https://github.com/jupyterlab/jupyterlab/pull/6087), [#5966](https://github.com/jupyterlab/jupyterlab/issues/5966)) -#### Printing +### Printing We now have a printing system that allows extensions to customize how documents and activities are printed. ([#5850](https://github.com/jupyterlab/jupyterlab/pull/5850), [#1314](https://github.com/jupyterlab/jupyterlab/issues/1314)) -#### Other User Facing Changes +### Other User Facing Changes - The launcher displays longer kernel names and supports keyboard navigation @@ -4185,7 +5347,7 @@ documents and activities are printed. ([#5682](https://github.com/jupyterlab/jupyterlab/pull/5682), [#2399](https://github.com/jupyterlab/jupyterlab/issues/2399)) -#### Settings +### Settings - The settings system has been rewritten ([#5470](https://github.com/jupyterlab/jupyterlab/pull/5470), @@ -4233,7 +5395,7 @@ There are new settings for many following items, including: ([#6026](https://github.com/jupyterlab/jupyterlab/pull/6026), [#4867](https://github.com/jupyterlab/jupyterlab/issues/4867)) -#### Command Line Changes +### Command Line Changes - Installing extensions will be quieter and adds a `--debug` to extension installing @@ -4261,7 +5423,7 @@ There are new settings for many following items, including: [#5695](https://github.com/jupyterlab/jupyterlab/pull/5695), [#5694](https://github.com/jupyterlab/jupyterlab/issues/5694)) -#### Extension Development Changes +### Extension Development Changes - We have rewritten how extensions provide keyboard shortcuts and interact with the settings system. If you previously defined @@ -4420,16 +5582,16 @@ There are new settings for many following items, including: `app.shell.add(widget)` or `app.shell.add(widget, 'main')`, see [here](https://github.com/jupyterlab/jupyterlab/blob/da8e7bda5eebd22319f59e5abbaaa9917872a7e8/packages/application/src/shell.ts#L500). -### [v0.35.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.35.0) +## [v0.35.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.35.0) -#### October 3, 2018 +### October 3, 2018 See the [JupyterLab 0.35.0](https://github.com/jupyterlab/jupyterlab/milestone/18?closed=1) milestone on GitHub for the full list of pull requests and issues closed. -#### Features +### Features - A notebook cell can now be readonly, reflecting its `enabled` metadata. @@ -4467,7 +5629,7 @@ closed. ([#5147](https://github.com/jupyterlab/jupyterlab/pull/5147), [#5042](https://github.com/jupyterlab/jupyterlab/issues/5042)) -#### Dark theme +### Dark theme - Show a dark splash screen when using a dark theme. ([#5339](https://github.com/jupyterlab/jupyterlab/pull/5339), @@ -4484,7 +5646,7 @@ closed. - Fix notebook cell dropdown legibility in a dark theme. ([#5168](https://github.com/jupyterlab/jupyterlab/issues/5168)) -#### Bug fixes +### Bug fixes - Various save options in the file menu and toolbar are now disabled when a file is not writable. @@ -4516,7 +5678,7 @@ closed. [#5340](https://github.com/jupyterlab/jupyterlab/pull/5340), [#5153](https://github.com/jupyterlab/jupyterlab/issues/5153)) -#### Build system +### Build system - Use Typescript 3.1. ([#5360](https://github.com/jupyterlab/jupyterlab/pull/5360)) @@ -4547,7 +5709,7 @@ closed. ([#5259](https://github.com/jupyterlab/jupyterlab/pull/5259), [#5257](https://github.com/jupyterlab/jupyterlab/issues/5257)) -#### For Developers +### For Developers - Default toolbar buttons can be overridden, and mime renderers can now specify toolbar buttons. @@ -4558,16 +5720,16 @@ closed. registry, service manager, and command linker. ([#5291](https://github.com/jupyterlab/jupyterlab/pull/5291)) -### [v0.34.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.34.0) +## [v0.34.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.34.0) -#### August 18, 2018 +### August 18, 2018 See the [JupyterLab 0.34.0](https://github.com/jupyterlab/jupyterlab/milestone/16?closed=1) milestone on GitHub for the full list of pull requests and issues closed. -#### Key Features +### Key Features - Notebooks, consoles, and text files now have access to completions for local tokens. @@ -4577,7 +5739,7 @@ closed. - Added "Open From Path..."" to top level `File` menu. - Added "Copy Download Link" to context menu for files. -#### Changes for Developers +### Changes for Developers - Notebooks, consoles, and text files now have access to completions for local tokens. If a text file has a running kernel associated @@ -4686,7 +5848,7 @@ closed. `ServerConnection`. ([#5111](https://github.com/jupyterlab/jupyterlab/pull/5111)) -#### Other Changes +### Other Changes - Added the pipe (`|`) character as a CSV delimiter option. ([#5112](https://github.com/jupyterlab/jupyterlab/pull/5112)) @@ -4707,7 +5869,7 @@ closed. ([#5097](https://github.com/jupyterlab/jupyterlab/pull/5097) and [#5130](https://github.com/jupyterlab/jupyterlab/pull/5130)) -#### Bug Fixes +### Bug Fixes - Fixed a bug in the rendering of the "New Notebook" item of the command palette. @@ -4721,7 +5883,7 @@ closed. than sometimes selecting it for a rename. ([#5101](https://github.com/jupyterlab/jupyterlab/pull/5101)) -### [v0.33.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.33.0) +## [v0.33.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.33.0) ### July 26, 2018 @@ -4730,9 +5892,22 @@ See the [JupyterLab milestone on GitHub for the full list of pull requests and issues closed. -#### Key Features: +### Key Features: + +- [No longer in beta](#no-longer-in-beta) +- [Workspaces](#workspaces) +- [Menu items](#menu-items) +- [Keyboard shortcuts](#keyboard-shortcuts) +- [Command palette items](#command-palette-items) +- [Settings](#settings) +- [Larger file uploads](#larger-file-uploads) +- [Extension management and installation](#extension-management-and-installation) +- [Interface changes](#interface-changes) +- [Renderers](#renderers) +- [Changes for developers](#changes-for-developers) +- [Other fixes](#other-fixes) -#### No longer in beta +### No longer in beta In JupyterLab 0.33, we removed the "Beta" label to better signal that JupyterLab is ready for users to use on a daily basis. The extension @@ -4741,7 +5916,7 @@ details. ([#4898](https://github.com/jupyterlab/jupyterlab/issues/4898), [#4920](https://github.com/jupyterlab/jupyterlab/pull/4920)) -#### Workspaces +### Workspaces We added new workspace support, which enables you to have multiple saved layouts, including in different browser windows. See the @@ -4753,7 +5928,7 @@ layouts, including in different browser windows. See the [#3673](https://github.com/jupyterlab/jupyterlab/issues/3673), [#4780](https://github.com/jupyterlab/jupyterlab/pull/4780)) -#### Menu items +### Menu items - "Activate Previously Used Tab" added to the Tab menu (`Ctrl/Cmd Shift '`) to toggle between the previously active tabs in @@ -4784,7 +5959,7 @@ layouts, including in different browser windows. See the consistency (same for right sidebar). ([#3818](https://github.com/jupyterlab/jupyterlab/pull/3818)) -#### Keyboard shortcuts +### Keyboard shortcuts - "Save As..." given the keyboard shortcut `Ctrl/Cmd Shift S`. ([#4560](https://github.com/jupyterlab/jupyterlab/pull/4560)) @@ -4799,7 +5974,7 @@ layouts, including in different browser windows. See the `Shift Enter` as a Console setting. ([#4054](https://github.com/jupyterlab/jupyterlab/pull/4054)) -#### Command palette items +### Command palette items - "Notebook" added to the command palette to open a new notebook. ([#4812](https://github.com/jupyterlab/jupyterlab/pull/4812)) @@ -4831,7 +6006,7 @@ layouts, including in different browser windows. See the ([#4533](https://github.com/jupyterlab/jupyterlab/pull/4533), [#4510](https://github.com/jupyterlab/jupyterlab/pull/4510)) -#### Settings +### Settings - "fontFamily", "fontSize", and "lineHeight" settings added to the text editor advanced settings. @@ -4839,13 +6014,13 @@ layouts, including in different browser windows. See the - Solarized dark and light text editor themes from CodeMirror. ([#4445](https://github.com/jupyterlab/jupyterlab/pull/4445)) -#### Larger file uploads +### Larger file uploads - Support for larger file uploads (>15MB) when using Jupyter notebook server version >= 5.1. ([#4224](https://github.com/jupyterlab/jupyterlab/pull/4224)) -#### Extension management and installation +### Extension management and installation - New extension manager for installing JupyterLab extensions from npm within the JupyterLab UI. You can enable this from the Advanced @@ -4858,7 +6033,7 @@ layouts, including in different browser windows. See the yarn](https://github.com/yarnpkg/yarn/issues/5935) is fixed. ([#4804](https://github.com/jupyterlab/jupyterlab/pull/4804)) -#### Interface changes +### Interface changes - Wider tabs in the main working area to show longer filenames. ([#4801](https://github.com/jupyterlab/jupyterlab/pull/4801)) @@ -4874,7 +6049,7 @@ layouts, including in different browser windows. See the [#3957](https://github.com/jupyterlab/jupyterlab/issues/3957), [#4966](https://github.com/jupyterlab/jupyterlab/pull/4966)) -#### Renderers +### Renderers - JupyterLab now ships with a Vega4 renderer by default (upgraded from Vega3). @@ -4888,7 +6063,7 @@ layouts, including in different browser windows. See the - Javascript execution in notebook cells has been re-enabled. ([#4515](https://github.com/jupyterlab/jupyterlab/pull/4682)) -#### Changes for developers +### Changes for developers - A new signal for observing application dirty status state changes. ([#4840](https://github.com/jupyterlab/jupyterlab/issues/4840)) @@ -5033,7 +6208,7 @@ Changes in the JupyterLab code infrastructure include: - Various process utilities were moved to `jupyterlab_server`. ([#4696](https://github.com/jupyterlab/jupyterlab/pull/4696)) -#### Other fixes +### Other fixes - Fixed a rendering bug with the Launcher in single-document mode. ([#4805](https://github.com/jupyterlab/jupyterlab/pull/4805)) @@ -5075,9 +6250,9 @@ Changes in the JupyterLab code infrastructure include: strings. ([#4480](https://github.com/jupyterlab/jupyterlab/pull/4480)) -### [Beta 2 (v0.32.0)](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.32.0) +## [Beta 2 (v0.32.0)](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.32.0) -#### Apr 16, 2018 +### Apr 16, 2018 This is the second in the JupyterLab Beta series of releases. It contains many enhancements, bugfixes, and refinements, including: @@ -5122,13 +6297,13 @@ contains many enhancements, bugfixes, and refinements, including: - Handle asynchronous comm messages in the services library more correctly (Note: this means `@jupyterlab/services` is now at version 2.0!) - ([\[#4115\](https://github.com/jupyterlab/jupyterlab/issues/4115)](https://github.com/jupyterlab/jupyterlab/pull/4115)). + (\[[#4115](https://github.com/jupyterlab/jupyterlab/issues/4115)\](https://github.com/jupyterlab/jupyterlab/pull/4115)). - Display the kernel banner in the console when a kernel is restarted to mark the restart - ([\[#3663\](https://github.com/jupyterlab/jupyterlab/issues/3663)](https://github.com/jupyterlab/jupyterlab/pull/3663)). + (\[[#3663](https://github.com/jupyterlab/jupyterlab/issues/3663)\](https://github.com/jupyterlab/jupyterlab/pull/3663)). - Many tweaks to the UI, as well as better error handling. -### [Beta 1 (v0.31.0)](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.31.0) +## [Beta 1 (v0.31.0)](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.31.0) ### Jan 11, 2018 @@ -5159,9 +6334,9 @@ contains many enhancements, bugfixes, and refinements, including: -### [v0.30.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.30.0) +## [v0.30.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.30.0) -#### Dec 05, 2017 +### Dec 05, 2017 - Semantic menus: - Settings editor now allows comments and provides setting validation: @@ -5182,16 +6357,16 @@ contains many enhancements, bugfixes, and refinements, including: for unreleased JavaScript and shows the red banner at the top of the page. -### [v0.29.2](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.29.2) +## [v0.29.2](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.29.2) -#### Nov 17, 2017 +### Nov 17, 2017 Bug fix for file browser right click handling. -### [v0.29.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.29.0) +## [v0.29.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.29.0) -#### Nov 09, 2017 +### Nov 09, 2017 - Create new view of cell in cell context menu. [#3159](https://github.com/jupyterlab/jupyterlab/issues/3159) @@ -5203,9 +6378,9 @@ Bug fix for file browser right click handling. - Standalone Cell Example. [#3155](https://github.com/jupyterlab/jupyterlab/issues/3155) -### [v0.28.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.28.0) +## [v0.28.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.28.0) -#### Oct 16, 2017 +### Oct 16, 2017 This release generally focuses on developer and extension author enhancements and general bug fixes. @@ -5227,9 +6402,9 @@ enhancements and general bug fixes. [#2974](https://github.com/jupyterlab/jupyterlab/issues/2974) - Numerous bug fixes and style enhancements. -### [v0.27.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.27.0) +## [v0.27.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.27.0) -#### Aug 23, 2017 +### Aug 23, 2017 - Added support for dynamic theme loading. @@ -5241,7 +6416,7 @@ enhancements and general bug fixes. [#2867](https://github.com/jupyterlab/jupyterlab/issues/2867) - Numerous bug fixes and style improvements. -### [v0.26.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.26.0) +## [v0.26.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.26.0) ### Jul 21, 2017 @@ -5254,7 +6429,7 @@ enhancements and general bug fixes. better use of the widget lifecycle: -### [v0.25.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.25.0) +## [v0.25.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.25.0) ### Jul 07, 2017 @@ -5272,7 +6447,7 @@ enhancements and general bug fixes. - Numerous bug fixes and style updates. -### [v0.24.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.24.0) +## [v0.24.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.24.0) ### Jun 16, 2017 @@ -5295,7 +6470,7 @@ enhancements and general bug fixes. [#2410](https://github.com/jupyterlab/jupyterlab/issues/2410) - Numerous bug fixes and style improvements. -### [v0.23.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.23.0) +## [v0.23.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.23.0) ### Jun 02, 2017 @@ -5311,9 +6486,9 @@ enhancements and general bug fixes. - Various bug fixes and style improvements. -### [v0.22.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.22.0) +## [v0.22.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.22.0) -#### May 18, 2017 +### May 18, 2017 - Export To... for notebooks. @@ -5338,9 +6513,9 @@ enhancements and general bug fixes. - Cleanup, bug fixes, and style updates. -### [v0.20.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.20.0) +## [v0.20.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.20.0) -#### Apr 21, 2017 +### Apr 21, 2017 Release Notes: @@ -5357,9 +6532,9 @@ Release Notes: Numerous bug fixes and improvements. -### [v0.19.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.19.0) +## [v0.19.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.19.0) -#### Apr 04, 2017 +### Apr 04, 2017 Mainly backend-focused release with compatibility with Phosphor 1.0 and a big refactor of session handling (the ClientSession class) that @@ -5371,9 +6546,9 @@ big split. -### [v0.18.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.18.0) +## [v0.18.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.18.0) -#### Mar 21, 2017 +### Mar 21, 2017 - Split the repository into multiple packages that are managed using the lerna build tool. @@ -5382,9 +6557,9 @@ big split. - Numerous bug fixes and style updates. -### [v0.17.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.17.0) +## [v0.17.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.17.0) -#### Mar 01, 2017 +### Mar 01, 2017 - Upgrade to new `@phosphor` packages * brings a new Command Palette interaction that should be more intuitive, and restores the ability @@ -5399,9 +6574,9 @@ big split. - Numerous style updates and bug fixes. -### [v0.16.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.16.0) +## [v0.16.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.16.0) -#### Feb 09, 2017 +### Feb 09, 2017 - Adds a Cell Tools sidebar that allows you to edit notebook cell metadata. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ddfdf8ce8b54..a389d39bd1ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,5 +4,5 @@ If you're reading this section, you're probably interested in contributing to JupyterLab. Welcome and thanks for your interest in contributing! Please take a look at Contributing to Jupyterlab on -[Read the Docs](https://jupyterlab.readthedocs.io/en/3.6.x/developer/contributing.html) or +[Read the Docs](https://jupyterlab.readthedocs.io/en/stable/developer/contributing.html) or [Repo docs](docs/source/developer/contributing.rst) (for the latest). diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index cf33c3b29731..000000000000 --- a/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM mambaorg/micromamba:0.14.0 as build - -# Install basic tools -RUN micromamba install -qy -c conda-forge python nodejs yarn \ - && useradd --shell /bin/bash jovyan \ - && chown jovyan $HOME - -# Install npm packages - faster build thanks to caching -## package_json.tar.gz contains all package.json files using -## `tar cvf package_json.tar.gz package.json packages/*/package.package_json` -ADD ./package_json.tar.gz /tmp/jupyterlab-dev -COPY yarn.lock /tmp/jupyterlab-dev - -RUN cd /tmp/jupyterlab-dev \ - && yarn install --ignore-scripts - -# Install python dependencies - faster build thanks to caching -COPY setup.cfg /tmp - -RUN list_package=$(python -c "from configparser import ConfigParser; c = ConfigParser(); c.read('/tmp/setup.cfg'); print(' '.join(c['options']['install_requires'].strip().splitlines()))") \ - && micromamba install -qy -c conda-forge $list_package \ - && micromamba clean -ay \ - && rm /tmp/setup.cfg - -# Install JupyterLab -COPY --chown=jovyan ./builder/ /tmp/jupyterlab-dev/builder/ -COPY --chown=jovyan ./buildutils/ /tmp/jupyterlab-dev/buildutils/ -COPY --chown=jovyan ./dev_mode/ /tmp/jupyterlab-dev/dev_mode/ -COPY --chown=jovyan ./jupyterlab/ /tmp/jupyterlab-dev/jupyterlab/ -COPY --chown=jovyan ./packages/ /tmp/jupyterlab-dev/packages/ -COPY --chown=jovyan ./scripts/ /tmp/jupyterlab-dev/scripts/ -COPY --chown=jovyan ./*.* ./LICENSE /tmp/jupyterlab-dev/ - -RUN pushd /tmp/jupyterlab-dev \ - && pip install -e .[ui-tests] - -USER jovyan -WORKDIR ${HOME} - -ENV PATH="/home/micromamba/.local/bin:$PATH" - -RUN mkdir -p /home/micromamba/jlab_root - -COPY ./docker/jupyter_server_config.json /etc/jupyter/ - -EXPOSE 8888 - -ENTRYPOINT ["jupyter", "lab"] diff --git a/LICENSE b/LICENSE index 491063d867d6..882b961e1d23 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2021 Project Jupyter Contributors +Copyright (c) 2015-2022 Project Jupyter Contributors All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index d804fad88ff4..000000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,48 +0,0 @@ -include package.json -include LICENSE -include *.md -include pyproject.toml -include setup.py -include setup.cfg -include conftest.py - -# Documentation -graft docs -exclude docs/\#* -prune docs/api -prune docs/build - -# We must include the package_data files since include_package_data=True -# See https://github.com/pypa/setuptools/issues/1461 -include jupyterlab/staging/* -include jupyterlab/staging/templates/* -include jupyterlab/staging/.yarnrc -graft jupyterlab/static -graft jupyterlab -graft jupyterlab/tests -graft jupyterlab/tests/mock_packages -graft jupyterlab/themes -graft jupyterlab/schemas -graft jupyter-config -recursive-include jupyterlab *.js - -prune jupyterlab/**/node_modules -prune jupyterlab/staging/build - -recursive-exclude jupyterlab *.pyc -recursive-exclude jupyterlab *.js.map - -# Galata -include galata/README.md -include galata/jupyter_server_test_config.py -include galata/update_snapshots.py -include galata/*.js -recursive-include galata/media *.* -graft galata/src -graft galata/style -graft galata/test - -# Docker -include Dockerfile -include .dockerignore -recursive-include docker *.json diff --git a/README.md b/README.md index 7a35e5b92847..6593658e3e47 100644 --- a/README.md +++ b/README.md @@ -9,26 +9,24 @@ [![PyPI version](https://badge.fury.io/py/jupyterlab.svg)](https://badge.fury.io/py/jupyterlab) [![Downloads](https://static.pepy.tech/badge/jupyterlab/month)](https://pepy.tech/project/jupyterlab) -[![Build Status](https://github.com/jupyterlab/jupyterlab/workflows/Linux%20Tests/badge.svg)](https://github.com/jupyterlab/jupyterlab/actions?query=branch%3Amaster+workflow%3A%22Linux+Tests%22) -[![Build Status](https://github.com/jupyterlab/jupyterlab/workflows/Windows%20Tests/badge.svg)](https://github.com/jupyterlab/jupyterlab/actions?query=branch%3Amaster+workflow%3A%22Windows+Tests%22) +[![Build Status](https://github.com/jupyterlab/jupyterlab/workflows/Linux%20Tests/badge.svg)](https://github.com/jupyterlab/jupyterlab/actions?query=branch%3Amain+workflow%3A%22Linux+Tests%22) +[![Build Status](https://github.com/jupyterlab/jupyterlab/workflows/Windows%20Tests/badge.svg)](https://github.com/jupyterlab/jupyterlab/actions?query=branch%3Amain+workflow%3A%22Windows+Tests%22) [![Documentation Status](https://readthedocs.org/projects/jupyterlab/badge/?version=stable)](http://jupyterlab.readthedocs.io/en/stable/) [![Crowdin](https://badges.crowdin.net/jupyterlab/localized.svg)](https://crowdin.com/project/jupyterlab) [![GitHub](https://img.shields.io/badge/issue_tracking-github-blue.svg)](https://github.com/jupyterlab/jupyterlab/issues) [![Discourse](https://img.shields.io/badge/help_forum-discourse-blue.svg)](https://discourse.jupyter.org/c/jupyterlab) [![Gitter](https://img.shields.io/badge/social_chat-gitter-blue.svg)](https://gitter.im/jupyterlab/jupyterlab) +[![Gitpod](https://img.shields.io/badge/gitpod_editor-open-blue.svg)](https://gitpod.io/#https://github.com/jupyterlab/jupyterlab) -[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/5a5eb6b?urlpath=lab/tree/demo) - -[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/jupyterlab/jupyterlab) +[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/75ab1750f37b27db8e135c2c4f2139da6b641609?urlpath=lab/tree/demo) An extensible environment for interactive and reproducible computing, based on the -Jupyter Notebook and Architecture. [Currently ready for users.](https://blog.jupyter.org/jupyterlab-is-ready-for-users-5a6f039b8906) +Jupyter Notebook and Architecture. [JupyterLab](http://jupyterlab.readthedocs.io/en/stable/) is the next-generation user interface for [Project Jupyter](https://jupyter.org) offering all the familiar building blocks of the classic Jupyter Notebook (notebook, terminal, text editor, file browser, rich outputs, etc.) in a flexible and powerful user interface. -JupyterLab will eventually replace the classic Jupyter Notebook. JupyterLab can be extended using [npm](https://www.npmjs.com/) packages that use our public APIs. The _prebuilt_ extensions can be distributed @@ -36,52 +34,37 @@ via [PyPI](https://pypi.org/search/?q=jupyterlab&o=-created&c=Framework+%3A%3A+J conda, and other package managers. The _source_ extensions can be installed directly from npm (search for [jupyterlab-extension](https://www.npmjs.com/search?q=keywords:jupyterlab-extension)) but require an additional build step. You can also find JupyterLab extensions exploring GitHub topic [jupyterlab-extension](https://github.com/topics/jupyterlab-extension). -To learn more about extensions, see the [user documentation](https://jupyterlab.readthedocs.io/en/3.6.x/user/extensions.html). - -The current JupyterLab releases are suitable for general -usage, and the extension APIs will continue to -evolve for JupyterLab extension developers. +To learn more about extensions, see the [user documentation](https://jupyterlab.readthedocs.io/en/stable/user/extensions.html). Read the current JupyterLab documentation on [ReadTheDocs](http://jupyterlab.readthedocs.io/en/stable/). -______________________________________________________________________ +--- ## Getting started ### Installation -JupyterLab can be installed using [conda](https://docs.conda.io/en/latest/), [mamba](https://mamba.readthedocs.io/en/latest/) or [pip](https://docs.python.org/3.6/installing/index.html). For more detailed instructions, consult the [installation guide](http://jupyterlab.readthedocs.io/en/3.6.x/getting_started/installation.html). - -Project installation instructions from the git sources are available in the [contributor documentation](CONTRIBUTING.md). - -### mamba and conda - -If you use `mamba` or `conda`, you can install it with: - -```shell -mamba install -c conda-forge jupyterlab -``` - -or - -```shell -conda install -c conda-forge jupyterlab -``` +If you use [conda](https://docs.conda.io/en/latest/), [mamba](https://mamba.readthedocs.io/en/latest/), or [pip](https://docs.python.org/3/installing/index.html), you can install JupyterLab with one of the following commands. -### pip +- If you use conda: + ```shell + conda install -c conda-forge jupyterlab + ``` +- If you use mamba: + ```shell + mamba install -c conda-forge jupyterlab + ``` +- If you use pip: + ```shell + pip install jupyterlab + ``` + If installing using `pip install --user`, you must add the user-level `bin` directory to your `PATH` environment variable in order to launch `jupyter lab`. If you are using a Unix derivative (e.g., FreeBSD, GNU/Linux, macOS), you can do this by running `export PATH="$HOME/.local/bin:$PATH"`. If you are using a macOS version that comes with Python 2, run `pip3` instead of `pip`. -If you use `pip`, you can install it with: - -```shell -pip install jupyterlab -``` - -If installing using `pip install --user`, you must add the user-level `bin` directory to your `PATH` environment variable in order to launch `jupyter lab`. If you are using a Unix derivative (e.g., FreeBSD, GNU/Linux, macOS), you can do this by running `export PATH="$HOME/.local/bin:$PATH"`. If you are using a macOS version that comes with Python 2, run `pip3` instead of `pip`. +For more detailed instructions, consult the [installation guide](http://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html). Project installation instructions from the git sources are available in the [contributor documentation](CONTRIBUTING.md). #### Installing with Previous Versions of Jupyter Notebook -When using a version of Jupyter Notebook earlier than 5.3, the following command must be run -after installation to enable the JupyterLab server extension: +When using a version of Jupyter Notebook earlier than 5.3, the following command must be run after installing JupyterLab to enable the JupyterLab server extension: ```bash jupyter serverextension enable --py jupyterlab --sys-prefix @@ -95,7 +78,7 @@ Start up JupyterLab using: jupyter lab ``` -JupyterLab will open automatically in the browser. See the [documentation](http://jupyterlab.readthedocs.io/en/3.6.x/getting_started/starting.html) for additional details. +JupyterLab will open automatically in the browser. See the [documentation](http://jupyterlab.readthedocs.io/en/stable/getting_started/starting.html) for additional details. If you encounter an error like "Command 'jupyter' not found", please make sure `PATH` environment variable is set correctly. Alternatively, you can start up JupyterLab using `~/.local/bin/jupyter lab` without changing the `PATH` environment variable. @@ -107,9 +90,9 @@ The latest versions of the following browsers are currently _known to work_: - Chrome - Safari -See our [documentation](http://jupyterlab.readthedocs.io/en/3.6.x/getting_started/installation.html) for additional details. +See our [documentation](http://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html) for additional details. -______________________________________________________________________ +--- ## Getting help @@ -117,30 +100,30 @@ We encourage you to ask questions on the [Discourse forum](https://discourse.jup ### Bug report -To report a bug please read the [guidelines](https://jupyterlab.readthedocs.io/en/3.6.x/getting_started/issue.html) and then open a [Github issue](https://github.com/jupyterlab/jupyterlab/issues/new?labels=bug%2C+status%3ANeeds+Triage&template=bug_report.md). To keep resolved issues self-contained, the [lock bot](https://github.com/apps/lock) will lock closed issues as resolved after a period of inactivity. If a related discussion is still needed after an issue is locked, please open a new issue and reference the old issue. +To report a bug please read the [guidelines](https://jupyterlab.readthedocs.io/en/stable/getting_started/issue.html) and then open a [Github issue](https://github.com/jupyterlab/jupyterlab/issues/new?labels=bug%2C+status%3ANeeds+Triage&template=bug_report.md). To keep resolved issues self-contained, the [lock bot](https://github.com/apps/lock) will lock closed issues as resolved after a period of inactivity. If a related discussion is still needed after an issue is locked, please open a new issue and reference the old issue. ### Feature request -We also welcome suggestions for new features as they help make the project more useful for everyone. To request a feature please use the [feature request template](https://github.com/jupyterlab/jupyterlab/issues/new?template=feature_request.md). +We also welcome suggestions for new features as they help make the project more useful for everyone. To request a feature please use the [feature request template](https://github.com/jupyterlab/jupyterlab/issues/new?labels=enhancement%2C+status%3ANeeds+Triage&template=feature_request.md). -______________________________________________________________________ +--- ## Development ### Extending JupyterLab -To start developing an extension for JupyterLab, see the [developer documentation](https://jupyterlab.readthedocs.io/en/3.6.x/extension/extension_dev.html) and the [API docs](https://jupyterlab.readthedocs.io/en/3.6.x/api/). +To start developing an extension for JupyterLab, see the [developer documentation](https://jupyterlab.readthedocs.io/en/stable/extension/extension_dev.html) and the [API docs](https://jupyterlab.readthedocs.io/en/stable/api/). ### Contributing -To contribute code or documentation to JupyterLab itself, please read the [contributor documentation](https://jupyterlab.readthedocs.io/en/3.6.x/developer/contributing.html). +To contribute code or documentation to JupyterLab itself, please read the [contributor documentation](https://jupyterlab.readthedocs.io/en/stable/developer/contributing.html). JupyterLab follows the Jupyter [Community Guides](https://jupyter.readthedocs.io/en/latest/community/content-community.html). ### License JupyterLab uses a shared copyright model that enables all contributors to maintain the -copyright on their contributions. All code is licensed under the terms of the revised [BSD license](https://github.com/jupyterlab/jupyterlab/blob/3.6.x/LICENSE). +copyright on their contributions. All code is licensed under the terms of the revised [BSD license](https://github.com/jupyterlab/jupyterlab/blob/4.0.x/LICENSE). ### Team @@ -148,23 +131,23 @@ JupyterLab is part of [Project Jupyter](http://jupyter.org/) and is developed by JupyterLab's current maintainers are listed in alphabetical order, with affiliation, and main areas of contribution: -- Mehmet Bektas, Splunk (general development, extensions). +- Mehmet Bektas, Netflix (general development, extensions). - Alex Bozarth, IBM (general development, extensions). - Eric Charles, Datalayer, (general development, extensions). - FrÊdÊric Collonval, QuantStack (general development, extensions). - Martha Cryan, IBM (general development, extensions). -- Afshin Darian, Two Sigma (co-creator, application/high-level architecture, +- Afshin Darian, QuantStack (co-creator, application/high-level architecture, prolific contributions throughout the code base). - Vidar T. Fauske, JPMorgan Chase (general development, extensions). - Brian Granger, AWS (co-creator, strategy, vision, management, UI/UX design, architecture). -- Jason Grout, Bloomberg (co-creator, vision, general development). +- Jason Grout, Databricks (co-creator, vision, general development). - Michał Krassowski, University of Oxford (general development, extensions). - Max Klein, JPMorgan Chase (UI Package, build system, general development, extensions). - Gonzalo PeÃąa-Castellanos, QuanSight (general development, i18n, extensions). - Fernando Perez, UC Berkeley (co-creator, vision). - Isabela Presedo-Floyd, QuanSight Labs (design/UX). -- Steven Silvester, Apple (co-creator, release management, packaging, +- Steven Silvester, MongoDB (co-creator, release management, packaging, prolific contributions throughout the code base). - Jeremy Tuloup, QuantStack (general development, extensions). @@ -182,7 +165,7 @@ Maintainer emeritus: This list is provided to give the reader context on who we are and how our team functions. To be listed, please submit a pull request with your information. -______________________________________________________________________ +--- ### Weekly Dev Meeting @@ -190,6 +173,8 @@ We have videoconference meetings every week where we discuss what we have been w Anyone is welcome to attend, if they would like to discuss a topic or just listen in. -- When: Wednesdays [9AM Pacific Time](https://www.thetimezoneconverter.com/?t=9%3A00%20am&tz=San%20Francisco&) +- When: Wednesdays [9:00 AM Pacific Time (USA)](https://www.thetimezoneconverter.com/?t=9%3A00%20am&tz=San%20Francisco&) - Where: [`jovyan` Zoom](https://zoom.us/my/jovyan?pwd=c0JZTHlNdS9Sek9vdzR3aTJ4SzFTQT09) - What: [Meeting notes](https://hackmd.io/Y7fBMQPSQ1C08SDGI-fwtg?both) + +> Notes are archived on [GitHub JupyterLab team compass](https://github.com/jupyterlab/team-compass/issues). diff --git a/RELEASE.md b/RELEASE.md index 905a15f7a92e..4688b471cf70 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -2,10 +2,138 @@ This document guides a contributor through creating a release of JupyterLab. +## The JupyterLab Release Process + +JupyterLab follows [semver](https://semver.org/) for the versioning of the Python and JavaScript packages. + +### Release Timeline + +Although the commitments listed below are "best effort", the JupyterLab team tries to follow a couple of guidelines: + +- one major version per year, which usually includes API breaking changes +- several minor versions per year that include new features but no API breaking changes +- support and bug fixes on a couple of final releases (by backporting PRs and releasing from release branches) + +Release Plans are tracked in dedicated issues, and are closed when the final release. See the following two issues as an example: + +- [3.3 Release Plan](https://github.com/jupyterlab/jupyterlab/issues/11643) +- [4.0 Release Plan](https://github.com/jupyterlab/jupyterlab/issues/9647) + +### Alpha Releases + +Alpha releases have a fairly low bar. Their purpose is to start putting the new JupyterLab version into the hands of users and extension authors. + +The requirements for an alpha release should be that JupyterLab can be installed and run. Bugs and breaking changes are accepted. + +### Beta Releases + +Beta releases usually try to not have breaking changes in the API, although breaking changes can sometimes happen during that phase if they were missed during the alpha stage. + +The recommended time period for the Beta phase is a minimum of 2 weeks. + +The draft changelog describing user-facing changes will be published with the first Beta release. + +The community of extension developers and active users will be invited to commence testing the new Beta release including the draft user-facing changelog, and an invitation to open issues for any major: + +- regressions, +- usability problems +- points needing clarification (or inclusion) in the changelog, and +- points needing clarification in the extension porting guide. + +The start of the Beta-testing period will be announced on Jupyter mailing group and Jupyter Discourse for major releases, and only via a Discourse post for minor releases. + +All bug reports raised during the Beta-testing period should be triaged (but not necessarily addressed) before releasing the first release candidate. + +### Release Candidates + +Release Candidates (RC) are a signal to the extension developer community that they should start migrating to the new version to test it. At that point we consider the software stable. + +The RC stage is often a good time to address final release documentation changes or minor UX tweaks. During the RC phase, the JupyterLab developers and maintainers start updating third-party extensions over to the new version to test it. This work during the RC phase, and giving time for feedback from extension developers, can take up to a couple of weeks. + +The recommended time period for the Release Candidate phase is a minimum of 1 week for minor releases, and 2 weeks for major releases. + +## Automated Releases with the Jupyter Releaser + +The recommended way to make a release is to use [`jupyter_releaser`](https://jupyter-releaser.readthedocs.io/en/latest/how_to_guides/convert_repo_from_repo.html). + +### Workflow + +The full process is documented in https://jupyter-releaser.readthedocs.io/en/latest/get_started/making_release_from_repo.html. There is a recording of the full workflow on [YouTube](https://youtu.be/cdRvvyZvYKM). + +Here is a quick summary of the different steps. + +#### Communicate on Gitter + +It is good practice to let other maintainers and users know when starting a new release. + +For this we usually leave a small message in the `jupyterlab` room on Gitter: https://gitter.im/jupyterlab/jupyterlab. +Once the release is done, we also post a message with a link to the release notes, which include the changelog. + +#### 1. Prep Release + +The first step is to generate a new changelog entry for the upcoming release. + +We use the "Prep Release" workflow as documented here: https://jupyter-releaser.readthedocs.io/en/latest/get_started/making_release_from_repo.html#prep-release + +Go the Actions tab of the JupyterLab Repo and click on the `1. Prep Release` workflow: https://github.com/jupyterlab/jupyterlab/actions + +The workflow takes a couple of input parameters. Here is an overview with example values: + +| Input | Description | Example Value | +| ------------ | ------------------------------------------------------- | ----------------------- | +| Target | The owner/repo GitHub target | `jupyterlab/jupyterlab` | +| Branch | The branch to target | `main` | +| Version Spec | New Version Spec | `next` | +| Since | Use PRs since activity since this date or git reference | `v4.0.0a15` | + +The version spec follows the specification documented below in the [Bump Version](#bump-version) section. + +We can use `next` when making a `patch` release or a `build` pre-release. + +Click on "Run workflow", then once completed: + +1. Go to the Releases: https://github.com/jupyterlab/jupyterlab/releases +1. Check the draft GitHub Release has been created +1. Make edits to the changelog if needed. ⚠ī¸ If you make edits to the content of the GitHub Release, then don't forget to click on "Save Draft" and not "Publish Release". + +### 2. Publish Release + +#### PyPI and npm tokens + +Before running the "Publish Release" workflow, make sure you have been added to: + +- the `jupyterlab` project on PyPI: https://pypi.org/project/jupyterlab/ +- the `@jupyterlab` organization on npm: https://www.npmjs.com/settings/jupyterlab/packages + +Then create the PyPI and npm tokens. Check out the links in the [Jupyter Releaser Setup Documentation](https://jupyter-releaser.readthedocs.io/en/stable/get_started/making_release_from_releaser.html#set-up) for more information. + +#### Running the workflow + +On the [Actions](https://github.com/jupyterlab/jupyterlab/actions) page, select the "2. Publish Release" workflow. + +Fill in the information as mentioned in the body of the changelog PR, for example: + +| Input | Value | +| ------------------------------------- | ----- | +| The target branch | main | +| The URL of the draft GitHub release | | +| Comma separated list of steps to skip | | + +The "Publish Release" workflow: + +- builds and uploads the `jupyterlab` Python package to PyPI +- builds the `@jupyterlab/*` packages and uploads them to `npm` +- creates a new GitHub Release with the new changelog entry as release notes +- creates a PR to forward port the new changelog entry to the main branch (when releasing from a branch that is not the default) + +Then follow the [Post release candidate checklist](#post-release-candidate-checklist) if applicable. + +## Manual Release Process + Review `CONTRIBUTING.md`. Make sure all the tools needed to generate the built JavaScript files are properly installed. -## Creating a full release +### Creating a full release We publish the npm packages, a Python source package, and a Python universal binary wheel. We also publish a conda package on conda-forge (see below). See @@ -13,7 +141,7 @@ the Python docs on [package uploading](https://packaging.python.org/guides/tool-recommendations/) for twine setup instructions and for why twine is the recommended method. -## Getting a clean environment +### Getting a clean environment For convenience, here is a script for getting a completely clean repo. This makes sure that we don't have any extra tags or commits in our repo (especially @@ -26,7 +154,7 @@ Make sure you are running an sh-compatible shell, and it is set up to be able to source scripts/release_prep.sh ``` -## Bump version +### Bump version The next step is to bump the appropriate version numbers. We use [bump2version](https://github.com/c4urself/bump2version) to manage the Python @@ -37,23 +165,21 @@ Choose and run an appropriate command to bump version numbers for this release. | Command | Python Version Change | NPM Version change | | -------------------------- | --------------------- | ---------------------------------- | -| `jlpm bumpversion minor` | x.y.z-> x.(y+1).0.a0 | All a.b.c -> a.(b+10).0-alpha.0 | +| `jlpm bumpversion major` | x.y.z-> (x+1).0.0.a0 | All a.b.c -> a.(b+10).0-alpha.0 | +| `jlpm bumpversion minor` | x.y.z-> x.(y+1).0.a0 | All a.b.c -> a.(b+1).0-alpha.0 | | `jlpm bumpversion build` | x.y.z.a0-> x.y.z.a1 | All a.b.c-alpha.0 -> a.b.c-alpha.1 | | `jlpm bumpversion release` | x.y.z.a1-> x.y.z.b0 | All a.b.c-alpha.1 -> a.b.c-beta.0 | -| `jlpm bumpversion release` | x.y.z.a1-> x.y.z.rc0 | All a.b.c-alpha.1 -> a.b.c-rc.0 | +| `jlpm bumpversion release` | x.y.z.b1-> x.y.z.rc0 | All a.b.c-beta.1 -> a.b.c-rc.0 | | `jlpm bumpversion release` | x.y.z.rc0-> x.y.z | All a.b.c-rc0 -> a.b.c | | `jlpm bumpversion patch` | x.y.z -> x.y.(z+1) | Changed a.b.c -> a.b.(c+1) | -Note: For a minor release, we bump the JS packages by 10 versions so that +Note: For a major release, we bump the JS packages by 10 versions so that we are not competing amongst the minor releases for version numbers. We are essentially sub-dividing semver to allow us to bump minor versions of the JS packages as many times as we need to for minor releases of the top level JupyterLab application. -Other note: It's ok if `yarn-deduplicate` exits with a non zero code. This is -expected! - -### JS major release(s) +#### JS major release(s) In a major Python release, we can have one or more JavaScript packages also have a major bump. During the prerelease stage of a major release, if there is a @@ -62,6 +188,8 @@ that JS package: `jlpm bump:js:major [...packages]` +**NOTE** You should rebase before running `jlpm bump:js:major` to avoid a cascade of merge conflicts. + Results: - Python package is not affected. @@ -69,7 +197,7 @@ Results: - Packages that have already had a major bump in this prerelease cycle are not affected. - All affected packages changed to match the current release type of the Python package (`alpha`, `beta`, or `rc`). -## Publishing Packages +### Publishing Packages Now publish the JS packages @@ -101,7 +229,7 @@ from ipywidgets import IntSlider IntSlider() ``` -## Finish +### Finish Follow instructions printed at the end of the publish step above: @@ -117,50 +245,47 @@ These lines: ## Post release candidate checklist -- \[ \] Modify and run `python scripts/milestone_check.py` to check the issues assigned to this milestone -- \[ \] Write [release highlights](CHANGELOG.md), starting with: +- [ ] Modify and run `python scripts/milestone_check.py` to check the issues assigned to this milestone +- [ ] Write [release highlights](CHANGELOG.md), starting with: ```bash loghub jupyterlab/jupyterlab -m XXX -t $GITHUB_TOKEN --template scripts/release_template.txt ``` -- \[ \] Test the release candidate in a clean environment -- \[ \] Make sure the CI builds pass +- [ ] Test the release candidate in a clean environment +- [ ] Make sure the CI builds pass - The build will fail if we publish a new package because by default it is private. Use `npm access public @jupyterlab/` to make it public. - The build will fail if we forget to include `style/` in the `files:` of a package (it will fail on the `jupyter lab build` command because webpack cannot find the referenced styles to import. -- \[ \] Update the other repos: - - \[ \] https://github.com/jupyterlab/extension-cookiecutter-js - - \[ \] https://github.com/jupyterlab/extension-cookiecutter-ts - - \[ \] https://github.com/jupyterlab/mimerender-cookiecutter - - \[ \] https://github.com/jupyterlab/mimerender-cookiecutter-ts - - \[ \] https://github.com/jupyterlab/theme-cookiecutter - - \[ \] https://github.com/jupyterlab/jupyter-renderers -- \[ \] Add a tag to [ts cookiecutter](https://github.com/jupyterlab/extension-cookiecutter-ts) with the new JupyterLab version -- \[ \] Update the extension examples: - - \[ \] [Notebook toolbar button](https://github.com/jupyterlab/jupyterlab/blob/3.6.x/docs/source/extension/notebook.rst#adding-a-button-to-the-toolbar) -- \[ \] Update the [extension tutorial](https://github.com/jupyterlab/jupyterlab/blob/3.6.x/RELEASE.md#updating-the-extension-tutorial) -- \[ \] At this point, there may have been some more commits merged. Run `python scripts/milestone_check.py` to check the issues assigned to this milestone one more time. Update changelog if necessary. +- [ ] Update the other repos: + - [ ] https://github.com/jupyterlab/extension-template + - [ ] https://github.com/jupyterlab/jupyter-renderers +- [ ] Publish a release (with a **updated tag**) to the [extension template](https://github.com/jupyterlab/extension-template/releases) with the new JupyterLab version +- [ ] Update the extension examples: + - [ ] [Notebook toolbar button](https://github.com/jupyterlab/jupyterlab/blob/4.0.x/docs/source/extension/notebook.rst#adding-a-button-to-the-toolbar) + - [ ] [Notebook widget](https://github.com/jupyterlab/jupyterlab/blob/4.0.x/docs/source/extension/notebook.rst#adding-a-widget-to-the-notebook-header) +- [ ] Update the [extension tutorial](https://github.com/jupyterlab/jupyterlab/blob/4.0.x/RELEASE.md#updating-the-extension-tutorial) +- [ ] At this point, there may have been some more commits merged. Run `python scripts/milestone_check.py` to check the issues assigned to this milestone one more time. Update changelog if necessary. Now do the actual final release: -- \[ \] Run `jlpm run bumpversion release` to switch to final release -- \[ \] Push the commit and tags to master -- \[ \] Run `npm run publish:all` to publish the packages -- \[ \] Create a branch for the release and push to GitHub -- \[ \] Update the API [docs](#updating-api-docs) -- \[ \] Merge the PRs on the other repos and set the default branch of the - xckd repo -- \[ \] Publish to [conda-forge](https://github.com/jupyterlab/jupyterlab/blob/3.6.x/RELEASE.md#publishing-to-conda-forge). +- [ ] Run `jlpm run bumpversion release` to switch to final release +- [ ] Push the commit and tags to main +- [ ] Run `npm run publish:all` to publish the packages +- [ ] Create a branch for the release and push to GitHub +- [ ] Update the API [docs](#updating-api-docs) +- [ ] Merge the PRs on the other repos and set the default branch of the + xckd repo +- [ ] Publish to [conda-forge](https://github.com/jupyterlab/jupyterlab/blob/4.0.x/RELEASE.md#publishing-to-conda-forge). After a few days (to allow for possible patch releases), set up development for the next release: -- \[ \] Run `jlpm run bumpversion minor` to bump to alpha for the next alpha release -- \[ \] Put the commit and tags to master -- \[ \] Run `npm run publish:all` to publish the packages -- \[ \] Release the other repos as appropriate -- \[ \] Update version for [binder](https://github.com/jupyterlab/jupyterlab/blob/3.6.x/RELEASE.md#update-version-for-binder) +- [ ] Run `jlpm run bumpversion minor` to bump to alpha for the next alpha release +- [ ] Put the commit and tags to main +- [ ] Run `npm run publish:all` to publish the packages +- [ ] Release the other repos as appropriate +- [ ] Update version for [binder](https://github.com/jupyterlab/jupyterlab/blob/4.0.x/RELEASE.md#update-version-for-binder) ### Updating the extension tutorial @@ -182,6 +307,15 @@ git checkout -b BRANCH # whatever the new version is, e.g., 1.0 git rebase -i --root ``` +To seed the latest version of the extension template (first commit), you +can execute (assuming you are editing the first commit): + +```sh +copier copy --UNSAFE https://github.com/jupyterlab/extension-template . +# Fix any conflicts +git commit --amend '-S' +``` + "Edit" the commits that involve installing packages, so you can update the `package.json`. Amend the last commit to bump the version number in package.json in preparation for publishing to npm. Then skip down to the step below about @@ -196,10 +330,7 @@ updating package versions, then do the next steps instead. git checkout --orphan name-of-branch git rm -rf . git clean -dfx -cookiecutter -o initial path-to-local-extension-cookiecutter-ts -# Fill in the values from the previous branch package.json initial commit -cp -r initial/jupyterlab_apod . -rm -rf initial +copier copy --UNSAFE https://github.com/jupyterlab/extension-template . ``` - Create a new PR in JupyterLab. @@ -211,21 +342,21 @@ rm -rf initial #### Publishing extension tutorial changes -- Tag commits in the branch with the appropriate `branch-step` tag. If you are at the final commit, you can tag all commits with the below, replacing `BRANCH` with the branch name (e.g., `1.0-01-show-a-panel`) \`\`\`bash - git tag BRANCH-01-show-a-panel HEAD~4 - git tag BRANCH-02-show-an-image HEAD~3 - git tag BRANCH-03-style-and-attribute HEAD~2 - git tag BRANCH-04-refactor-and-refresh HEAD~1 - git tag BRANCH-05-restore-panel-state HEAD - - ``` +- Tag commits in the branch with the appropriate `branch-step` tag. If you are at the final commit, you can tag all commits with the below, setting `BRANCH` with the branch name (e.g., `1.0-01-show-a-panel`) + ```bash + export BRANCH= + git tag ${BRANCH}-01-show-a-panel HEAD~4 + git tag ${BRANCH}-02-show-an-image HEAD~3 + git tag ${BRANCH}-03-style-and-attribute HEAD~2 + git tag ${BRANCH}-04-refactor-and-refresh HEAD~1 + git tag ${BRANCH}-05-restore-panel-state HEAD ``` - Push the branch with the new tags ```bash - git push origin BRANCH --tags + git push origin ${BRANCH} --tags ``` Set the branch as the default branch (see `github.com/jupyterlab/jupyterlab_apod/settings/branches`). @@ -240,10 +371,10 @@ rm -rf initial ``` If you make a mistake and need to start over, clear the tags using the -following pattern (replacing `BRANCH` with the branch name): +following pattern: ```bash -git tag | grep BRANCH | xargs git tag -d +git tag | grep ${BRANCH} | xargs git tag -d ``` ### Publishing to conda-forge @@ -258,9 +389,9 @@ shasum -a 256 dist/*.tar.gz - Fork https://github.com/conda-forge/jupyterlab-feedstock - Create a PR with the version bump -- Update `recipe/meta.yaml` with the new version and md5 and reset the build number to 0. +- Update `recipe/meta.yaml` with the new version and sha256 and reset the build number to 0. -## Making a patch release +## Making a manual patch release - Backport the change to the previous release branch - Run the following script, where the package is in `/packages/package-folder-name` (note that multiple packages can be given, or no packages for a Python-only patch release): @@ -281,3 +412,68 @@ https://github.com/jupyter/repo2docker/pull/169/files This needs to be done in both the conda and pip buildpacks in both the frozen and non-frozen version of the files. + +## Making a Minor Release + +### Planning + +- Create a pinned issue +- Create a milestone +- Decide on a scope for the release and set a target final release date + +## Alpha and Beta Phase + +- Create a new branch from the previous release branch +- Use a ".x" in the branch name so we can continue to use it for patches +- Update branch and RTD config in `ensure_repo.ts` and run `jlpm integrity` to update links - source should be the previous release branch +- Update readthedocs branch config as appropriate +- Automated Release using "minor" - edit changelog for new section +- Move through alpha and beta phases as appropriate + +### RC Phase + +- Roll up the release notes using the "Use PRs with activity since the last stable git tag" option when running the workflows +- Update the release issue with an updated date + +### Final Release + +- Roll up the release notes using the "Use PRs with activity since the last stable git tag" option when running the workflows +- Close the release issue +- Rename milestone to use ".x" +- Make an announcement on Discourse + +## Making a Major Release + +### Planning + +- Create a pinned issue +- Create a milestone +- Decide on a scope for the release and set a target final release date + +### Alpha and Beta Phase + +- Update branch and RTD config in `ensure_repo.ts` and `jlpm integrity` to update links - source should be the previous branch +- Update readthedocs branch config as appropriate +- Automated Release using "major" - edit changelog for new section +- Move through alpha and beta phases as appropriate + +### RC Phase + +- Roll up the release notes using the "Use PRs with activity since the last stable git tag" option when running the workflows +- Create a new branch from the default branch with ".x" in the name so we can continue to use it for patches +- Update the release issue with an updated date + +### Final Release + +- Roll up the release notes using the "Use PRs with activity since the last stable git tag" option when running the workflows +- Close the release issue and rename milestone to use ".x" +- Make an announcement on Discourse +- Make a blog post + +## Postmortems + +Here is a list of previous issues that happened while releasing JupyterLab, that can be used as reference in case +new issues show up in the future: + +- HTTP Error 502: Bad Gateway (JupyterLab `4.0.0a23`): https://github.com/jupyterlab/jupyterlab/issues/12324 +- Degraded performance of npm publish (JupyterLab `4.0.0b2`): https://github.com/jupyterlab/jupyterlab/issues/14431 diff --git a/binder/README.md b/binder/README.md index b40415f436e5..81a7a5e61628 100644 --- a/binder/README.md +++ b/binder/README.md @@ -1,16 +1,32 @@ -This directory holds configuration files for https://mybinder.org/. +This directory holds configuration files for a development-focused +[Binder](https://mybinder.org). -A Binder instance can be launched by visiting this URL: +> For a more user-focused Binder use this URL: +> +> https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/master?urlpath=lab/tree/demo/Lorenz.ipynb -https://mybinder.org/v2/gh/jupyterlab/jupyterlab/master?urlpath=lab +A personal Binder instance can be launched by visiting this URL: -To check out a different version, just replace "master" with the desired -branch/tag name or commit hash. + https://mybinder.org/v2/gh/jupyterlab/jupyterlab/HEAD?urlpath=lab -If there is an error with the launched application, you can look at -`~/jupyterlab-dev.log` in a terminal to see the log. +To check out a different version, replace `HEAD` with the desired +branch, tag name, or commit hash. -Please note that this setup is developer focused. -For a more user-focused Binder use this URL: +## Reports -https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/master?urlpath=lab/tree/demo/Lorenz.ipynb +Once it launches, a number of reports are generated in `_reports_` which detail +aspects of development: + +- packages installed +- the duration and complexity of the `nodejs` and `python` package build process +- `jupyter_server` configuration information +- the final size of the as-built JS/CSS assets + +## Server Log + +Note that the log of the running application is also available, and can be +observed from a _Terminal_ with the command: + +```bash +tail -f .jupyter-server-log.txt +``` diff --git a/binder/environment.yml b/binder/environment.yml index 8b9002c7e965..d3549cdb430d 100644 --- a/binder/environment.yml +++ b/binder/environment.yml @@ -1,13 +1,65 @@ -name: example-environment +name: jupyterlab-dev + channels: - conda-forge + - nodefaults + dependencies: - - jupyterlab-link-share=0.2 + # runtimes + - nodejs >=18,<19 + - python =3.11 + # package managers + - pip + - yarn >=3,<4 + # build + - hatch-jupyter-builder >=0.3.2 + - hatchling >=1.5.0 + # run + - async-lru >=1.0.0 + - ipykernel + - jinja2 >=3.0.3 + - jupyter_core + - jupyter_server >=2.4.0,<3 + - jupyter-lsp >=2.0.0 + - jupyterlab_server >=2.19.0,<3 + - notebook-shim >=0.2 + - packaging + - tornado >=6.2.0 + - traitlets >=5.10.1 + # test + - coverage + - pytest >=7.0 + - pytest-check-links >=0.7 + - pytest-console-scripts + - pytest-cov + - pytest-jupyter-server >=0.5.3 + - pytest-timeout + - pytest-tornasync + - requests + - requests-cache + - virtualenv + # dev + - black-jupyter + - bump2version + - hatch + - pre-commit + - pytest-cov + - python-build + - ruff + # demo - jupyter-server-proxy - matplotlib-base - - nodejs=14 + - notebook >=7.0.4 - numpy - - pip - - python=3.8 - vega_datasets - xeus-python + # extra conda stuff + - jsonschema-with-format-nongpl + # jupyter-collaboration 1.2.0 + - jupyter_ydoc >=1.0.1,<2.0.0 + - ypy-websocket >=0.12.1,<0.13.0 + - jupyter_events >=0.7.0 + - jupyter_server_fileid >=0.7.0,<1 + - pip: + # can't be installed with `conda` in binder, due to `jupyterlab-link-share`` + - jupyter-collaboration ==1.2.0 diff --git a/binder/jupyter_notebook_config.py b/binder/jupyter_config.py similarity index 70% rename from binder/jupyter_notebook_config.py rename to binder/jupyter_config.py index 01d93235330b..ec1024a235fb 100644 --- a/binder/jupyter_notebook_config.py +++ b/binder/jupyter_config.py @@ -1,3 +1,8 @@ +"""An INSECURE configuration for Jupyter Server, intended only for mybinder.org.""" +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. +import logging + common = [ "--no-browser", "--debug", @@ -24,9 +29,9 @@ "jupyter", "lab", "--ServerApp.base_url={base_url}lab-spliced", + *common, + ">jupyterlab-spliced.log 2>&1", ] - + common - + [">jupyterlab-spliced.log 2>&1"] ) @@ -38,6 +43,10 @@ }, } -import logging - c.ServerApp.log_level = logging.DEBUG + +c.LabApp.dev_mode = True +c.LabApp.extensions_in_dev_mode = True +c.LabApp.skip_dev_build = True + +c.ContentsManager.allow_hidden = True diff --git a/binder/postBuild b/binder/postBuild index e3a51c06479b..493cc57391b4 100755 --- a/binder/postBuild +++ b/binder/postBuild @@ -1,6 +1,42 @@ -#!/bin/bash +#!/usr/bin/env bash + # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -set -euo pipefail -pip install -e .[dev] +# ensure no surprises from binder's "half" activation +source activate ${NB_PYTHON_PREFIX} + +# use strict and verbose shell settings +set -euxo pipefail + +# create log folder, named to appear at the top of the file browser +mkdir _reports_ + +# pre-install nodejs deps and build outside of editable python install +(time yarn) 2>&1 | tee _reports_/00_yarn.txt +(time yarn build:dev:prod:minimize:report) 2>&1 | tee _reports_/01_build.txt + +# hoist report to where a reviewer might see it +mv dev_mode/static/webpack-bundle-analyzer.html _reports_/ + +# overload best-effort versions from conda-forge for all deps +(time pip install -v -e .[dev] --no-build-isolation) 2>&1 | tee _reports_/02_pip_install.txt + +# copy configuration to well-known location +mkdir -p ~/.jupyter +cp binder/jupyter_config.py ~/.jupyter/ + +# capture configuration and debug information +(time pip list) 2>&1 | tee _reports_/03_pip_list.txt +(time pip check || echo FAIL) 2>&1 | tee _reports_/04_pip_check.txt +(time jupyter troubleshoot) 2>&1 | tee _reports_/10_troubleshoot.txt +(time jupyter notebook --show-config) 2>&1 | tee _reports_/11_notebook_show_config.txt +(time jupyter lab --show-config) 2>&1 | tee _reports_/12_lab_show_config.txt +(time jupyter server extension list) 2>&1 | tee _reports_/13_server_extension_list.txt +(time jupyter labextension list) 2>&1 | tee _reports_/14_labextension_list.txt + +# clean up egregious wastes of space +rm -rf \ + ~/.cache \ + dev_mode/stats.json \ + node_modules/@stdlib diff --git a/binder/start b/binder/start deleted file mode 100755 index 7b1afad27ca9..000000000000 --- a/binder/start +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -import sys -import shutil - -# using jupyter_notebook_config.py for now since Binder is still starting the -# classic notebook server -argv = sys.argv[1:] + [ - "--debug", - "--dev-mode", - "--extensions-in-dev-mode", - "--collaborative", - "--ContentsManager.allow_hidden=True", - "--config", - "binder/jupyter_notebook_config.py", -] -print(argv) - - -# Convert from jupyter-notebook based to jupyter-lab based start-up -def nb2jps(s): - return s.replace("jupyter-notebook", "jupyter-lab").replace("--NotebookApp.", "--ServerApp.") - - -new_argv = list(map(nb2jps, argv.copy())) -print(new_argv) - -with open(".startup_args.txt", "w") as fid: - fid.write(str(new_argv)) - -os.execv(shutil.which(new_argv[0]), new_argv) diff --git a/buildapi.py b/buildapi.py new file mode 100644 index 000000000000..d813e18f7e84 --- /dev/null +++ b/buildapi.py @@ -0,0 +1,38 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +# Custom build target that removes .js.map files for published +# dist files. +import glob +import json +import os +import subprocess + +from hatch_jupyter_builder import npm_builder +from packaging.version import Version + + +def builder(target_name, version, *args, **kwargs): + # Allow building from sdist without node. + if target_name == "wheel" and not os.path.exists("dev_mode"): + return + + npm_builder(target_name, version, *args, **kwargs) + + if version == "editable": + return + + files = glob.glob("jupyterlab/static/*.js.map") + for path in files: + os.remove(path) + + target = glob.glob("jupyterlab/static/package.json")[0] + with open(target) as fid: + npm_version = json.load(fid)["jupyterlab"]["version"] + + py_version = subprocess.check_output(["hatchling", "version"]) # noqa S603 S607 + py_version = py_version.decode("utf-8").strip() + + if Version(npm_version) != Version(py_version): + msg = "Version mismatch, please run `npm run prepare:python-release`" + raise ValueError(msg) diff --git a/builder/package.json b/builder/package.json index e7690f3a8c55..c3db9d6796ae 100644 --- a/builder/package.json +++ b/builder/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/builder", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Extension Builder", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -24,58 +24,54 @@ "metadata_schema.json", "lib/*.d.ts", "lib/*.js.map", - "lib/*.js" + "lib/*.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc", - "build:all": "npm run build", "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", "watch": "tsc -w --listEmittedFiles" }, "dependencies": { - "@lumino/algorithm": "^1.9.0", - "@lumino/application": "^1.31.4", - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/domutils": "^1.8.0", - "@lumino/dragdrop": "^1.13.0", - "@lumino/messaging": "^1.10.0", - "@lumino/properties": "^1.8.0", - "@lumino/signaling": "^1.10.0", - "@lumino/virtualdom": "^1.14.0", - "@lumino/widgets": "^1.37.2", - "ajv": "^6.12.3", - "commander": "~6.0.0", - "css-loader": "^5.0.1", + "@lumino/algorithm": "^2.0.1", + "@lumino/application": "^2.2.1", + "@lumino/commands": "^2.1.3", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/domutils": "^2.0.1", + "@lumino/dragdrop": "^2.1.3", + "@lumino/messaging": "^2.0.1", + "@lumino/properties": "^2.0.1", + "@lumino/signaling": "^2.1.2", + "@lumino/virtualdom": "^2.0.1", + "@lumino/widgets": "^2.3.0", + "ajv": "^8.12.0", + "commander": "^9.4.1", + "css-loader": "^6.7.1", "duplicate-package-checker-webpack-plugin": "^3.0.0", - "file-loader": "~6.0.0", - "fs-extra": "^9.0.1", + "fs-extra": "^10.1.0", "glob": "~7.1.6", "license-webpack-plugin": "^2.3.14", - "mini-css-extract-plugin": "~1.3.2", + "mini-css-extract-plugin": "^2.7.0", + "mini-svg-data-uri": "^1.4.4", "path-browserify": "^1.0.0", "process": "^0.11.10", - "raw-loader": "~4.0.0", "source-map-loader": "~1.0.2", - "style-loader": "~2.0.0", + "style-loader": "~3.3.1", "supports-color": "^7.2.0", - "svg-url-loader": "~6.0.0", - "terser-webpack-plugin": "^4.1.0", - "to-string-loader": "^1.1.6", - "url-loader": "~4.1.0", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0", - "webpack-merge": "^5.1.2", + "terser-webpack-plugin": "^5.3.7", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-merge": "^5.8.0", "worker-loader": "^3.0.2" }, "devDependencies": { "@types/fs-extra": "^9.0.1", "@types/glob": "^7.1.1", - "@types/node": "^14.6.1", + "@types/node": "^18.11.18", "@types/supports-color": "^5.3.0", "rimraf": "~3.0.0", - "typescript": "~4.1.3" + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/builder/src/build-labextension.ts b/builder/src/build-labextension.ts index b3ac22a59040..b346760b7f72 100644 --- a/builder/src/build-labextension.ts +++ b/builder/src/build-labextension.ts @@ -42,7 +42,7 @@ /////////////////////////////////////////////////////// import * as path from 'path'; -import commander from 'commander'; +import { program as commander } from 'commander'; import webpack from 'webpack'; import generateConfig from './extensionConfig'; import { stdout as colors } from 'supports-color'; @@ -57,26 +57,26 @@ commander 'url for build assets, if hosted outside the built extension' ) .option('--watch') - .action(async cmd => { - const mode = cmd.development ? 'development' : 'production'; - const corePath = path.resolve(cmd.corePath || process.cwd()); - const packagePath = path.resolve(cmd.args[0]); - const devtool = cmd.sourceMap ? 'source-map' : undefined; + .action(async (options, command) => { + const mode = options.development ? 'development' : 'production'; + const corePath = path.resolve(options.corePath || process.cwd()); + const packagePath = path.resolve(command.args[0]); + const devtool = options.sourceMap ? 'source-map' : undefined; const config = generateConfig({ packagePath, mode, corePath, - staticUrl: cmd.staticUrl, + staticUrl: options.staticUrl, devtool, - watchMode: cmd.watch + watchMode: options.watch }); const compiler = webpack(config); let lastHash: string | null = null; function compilerCallback(err: any, stats: any) { - if (!cmd.watch || err) { + if (!options.watch || err) { // Do not keep cache anymore compiler.purgeInputFileSystem(); } @@ -93,7 +93,7 @@ commander if (stats.hasErrors()) { console.error(info.errors); - if (!cmd.watch) { + if (!options.watch) { process.exit(2); } } @@ -108,7 +108,7 @@ commander } } - if (cmd.watch) { + if (options.watch) { compiler.hooks.watchRun.tap('WebpackInfo', () => { console.error('\nWatch Compilation startingâ€Ļ\n'); }); @@ -124,7 +124,7 @@ commander }); } - if (cmd.watch) { + if (options.watch) { compiler.watch(config[0].watchOptions || {}, compilerCallback); console.error('\nwebpack is watching the filesâ€Ļ\n'); } else { diff --git a/builder/src/build.ts b/builder/src/build.ts index c58e4b207a31..23060c2d15f6 100644 --- a/builder/src/build.ts +++ b/builder/src/build.ts @@ -4,6 +4,7 @@ |----------------------------------------------------------------------------*/ import MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import miniSVGDataURI from 'mini-svg-data-uri'; import * as webpack from 'webpack'; import * as fs from 'fs-extra'; @@ -204,15 +205,18 @@ export namespace Build { rules: [ { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, 'css-loader'] + use: [MiniCssExtractPlugin.loader, require.resolve('css-loader')] }, { test: /\.svg/, - use: [{ loader: 'svg-url-loader', options: { encoding: 'none' } }] + type: 'asset/inline', + generator: { + dataUrl: (content: any) => miniSVGDataURI(content.toString()) + } }, { test: /\.(cur|png|jpg|gif|ttf|woff|woff2|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - use: [{ loader: 'url-loader', options: { limit: 10000 } }] + type: 'asset' } ] }, diff --git a/builder/src/duplicate-package-checker-webpack-plugin.d.ts b/builder/src/duplicate-package-checker-webpack-plugin.d.ts index 9eaae2491c69..897d28d7c8a2 100644 --- a/builder/src/duplicate-package-checker-webpack-plugin.d.ts +++ b/builder/src/duplicate-package-checker-webpack-plugin.d.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + // Type definitions for duplicate-package-checker-webpack-plugin 2.1 // Project: https://github.com/darrenscerri/duplicate-package-checker-webpack-plugin#readme // Definitions by: Matt Traynham diff --git a/builder/src/extensionConfig.ts b/builder/src/extensionConfig.ts index f575a59dec72..389f59374b1b 100644 --- a/builder/src/extensionConfig.ts +++ b/builder/src/extensionConfig.ts @@ -32,7 +32,7 @@ function generateConfig({ }: IOptions = {}): webpack.Configuration[] { const data = require(path.join(packagePath, 'package.json')); - const ajv = new Ajv({ useDefaults: true }); + const ajv = new Ajv({ useDefaults: true, strict: false }); const validate = ajv.compile(require('../metadata_schema.json')); let valid = validate(data.jupyterlab ?? {}); if (!valid) { @@ -251,13 +251,13 @@ function generateConfig({ filename += '?v=[contenthash]'; } - const rules: any = [{ test: /\.html$/, type: 'file-loader' }]; + const rules: any = [{ test: /\.html$/, type: 'asset/resource' }]; if (mode === 'development') { rules.push({ test: /\.js$/, enforce: 'pre', - use: ['source-map-loader'] + use: [require.resolve('source-map-loader')] }); } @@ -286,7 +286,14 @@ function generateConfig({ if (mode === 'development') { const logPath = path.join(outputPath, 'build_log.json'); - fs.writeFileSync(logPath, JSON.stringify(config, null, ' ')); + function regExpReplacer(key: any, value: any) { + if (value instanceof RegExp) { + return value.toString(); + } else { + return value; + } + } + fs.writeFileSync(logPath, JSON.stringify(config, regExpReplacer, ' ')); } return config; } diff --git a/builder/src/mini-css-extract-plugin.d.ts b/builder/src/mini-css-extract-plugin.d.ts index 62c4e144a489..321acb2e502b 100644 --- a/builder/src/mini-css-extract-plugin.d.ts +++ b/builder/src/mini-css-extract-plugin.d.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + // We use our own declaration because the existing typings do not work with webpack 5 declare module 'mini-css-extract-plugin'; diff --git a/builder/src/webpack.config.base.ts b/builder/src/webpack.config.base.ts index 9d1c0ae7b6fc..7d598a64f56b 100644 --- a/builder/src/webpack.config.base.ts +++ b/builder/src/webpack.config.base.ts @@ -1,41 +1,38 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. - -import * as path from 'path'; import * as webpack from 'webpack'; -import crypto from 'crypto'; - -// Workaround for loaders using "md4" by default, which is not supported in FIPS-compliant OpenSSL -const cryptoOrigCreateHash = crypto.createHash; -crypto.createHash = (algorithm: string) => - cryptoOrigCreateHash(algorithm == 'md4' ? 'sha256' : algorithm); +import miniSVGDataURI from 'mini-svg-data-uri'; const rules = [ - { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - { test: /\.txt$/, use: 'raw-loader' }, - { test: /\.md$/, use: 'raw-loader' }, - { test: /\.(jpg|png|gif)$/, use: 'file-loader' }, - { test: /\.js.map$/, use: 'file-loader' }, + { test: /\.raw\.css$/, type: 'asset/source' }, + { + test: /(? miniSVGDataURI(content.toString()) } }, { @@ -43,9 +40,7 @@ const rules = [ // must be loaded as a raw string instead of data URIs. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.js$/, - use: { - loader: 'raw-loader' - } + type: 'asset/source' }, { test: /\.m?js$/, @@ -65,42 +60,12 @@ const rules = [ } ]; -// Map Phosphor files to Lumino files. -const stylePath = path.join( - path.dirname(require.resolve('@lumino/widgets/package.json')), - 'style' -); - -let phosphorAlias = {}; - -try { - phosphorAlias = { - '@phosphor/algorithm$': require.resolve('@lumino/algorithm'), - '@phosphor/application$': require.resolve('@lumino/application'), - '@phosphor/commands$': require.resolve('@lumino/commands'), - '@phosphor/coreutils$': require.resolve('@lumino/coreutils'), - '@phosphor/disposable$': require.resolve('@lumino/disposable'), - '@phosphor/domutils$': require.resolve('@lumino/domutils'), - '@phosphor/dragdrop$': require.resolve('@lumino/dragdrop'), - '@phosphor/dragdrop/style': stylePath, - '@phosphor/messaging$': require.resolve('@lumino/messaging'), - '@phosphor/properties$': require.resolve('@lumino/properties'), - '@phosphor/signaling': require.resolve('@lumino/signaling'), - '@phosphor/widgets/style': stylePath, - '@phosphor/virtualdom$': require.resolve('@lumino/virtualdom'), - '@phosphor/widgets$': require.resolve('@lumino/widgets') - }; -} catch (e) { - // no Phosphor shims required -} - const watch = process.argv.includes('--watch'); module.exports = { bail: !watch, module: { rules }, resolve: { - alias: phosphorAlias, fallback: { url: false, buffer: false, diff --git a/buildutils/package.json b/buildutils/package.json index d17b3a940685..5995006bcea7 100644 --- a/buildutils/package.json +++ b/buildutils/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/buildutils", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Build Utilities", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -19,7 +19,8 @@ "local-repository": "./lib/local-repository.js", "remove-dependency": "./lib/remove-dependency.js", "update-dependency": "./lib/update-dependency.js", - "update-dist-tag": "./lib/update-dist-tag.js" + "update-dist-tag": "./lib/update-dist-tag.js", + "update-staging-lock": "./lib/update-staging-lock.js" }, "directories": { "lib": "lib/" @@ -31,40 +32,42 @@ "template/package.json", "template/tsconfig.json", "template/src/index.ts", - "verdaccio.yml" + "verdaccio.yml", + "src/**/*.{ts,tsx}" ], "scripts": { - "build": "tsc", - "build:all": "npm run build", + "build": "tsc && cd template && npm run build", "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", "watch": "tsc -w --listEmittedFiles" }, "dependencies": { - "@lumino/coreutils": "^1.11.0", - "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/core": "^3.0.0", + "@yarnpkg/parsers": "^2.0.0", "child_process": "~1.0.2", - "commander": "~6.0.0", + "commander": "^9.4.1", "crypto": "~1.0.1", - "dependency-graph": "^0.9.0", - "fs-extra": "^9.0.1", + "dependency-graph": "^0.11.0", + "fs-extra": "^10.1.0", "glob": "~7.1.6", - "inquirer": "^7.1.0", + "inquirer": "^9.1.4", + "micromatch": "^4.0.2", "minimatch": "~3.0.4", "os": "~0.1.1", - "package-json": "^6.5.0", - "prettier": "~2.1.1", + "package-json": "^7.0.0", + "prettier": "~2.6.0", "process": "^0.11.10", "semver": "^7.3.2", - "sort-package-json": "~1.44.0", - "typescript": "~4.1.3", - "verdaccio": "^5.20.1" + "sort-package-json": "~1.53.1", + "typescript": "~5.0.4", + "verdaccio": "^5.25.0" }, "devDependencies": { "@types/fs-extra": "^9.0.1", "@types/glob": "^7.1.1", - "@types/inquirer": "^7.3.1", - "@types/node": "^14.6.1", - "@types/prettier": "~2.1.0", + "@types/inquirer": "^9.0.3", + "@types/micromatch": "^4.0.1", + "@types/node": "^18.11.18", + "@types/prettier": "~2.6.0", "rimraf": "~3.0.0" }, "publishConfig": { diff --git a/buildutils/src/add-sibling.ts b/buildutils/src/add-sibling.ts deleted file mode 100755 index 68d8884d78c3..000000000000 --- a/buildutils/src/add-sibling.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* ----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ - -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as utils from './utils'; - -/** - * Add an extension to the source tree of JupyterLab. - * It takes as an argument either a path to a directory - * on the local filesystem or a URL to a git repository. - * In the former case, it copies the directory into the - * source tree, in the latter it adds the repository as - * a git submodule. - * - * It also adds the relevant metadata to the build files. - */ - -// Make sure we have required command line arguments. -if (process.argv.length < 3) { - const msg = '** Must supply a target extension'; - process.stderr.write(msg); - process.exit(1); -} - -// Extract the desired git repository and repository name. -const target = process.argv[2]; -const basePath = path.resolve('.'); -let packageDirName = path.basename(target); - -let packagePath = path.resolve(target); -if (fs.existsSync(packagePath)) { - // Copy the package directory contents to the sibling package. - const newPackagePath = path.join(basePath, 'packages', packageDirName); - fs.copySync(packagePath, newPackagePath); - packagePath = newPackagePath; -} else { - // Otherwise treat it as a git reposotory and try to add it. - packageDirName = target.split('/').pop()!.split('.')[0]; - packagePath = path.join(basePath, 'packages', packageDirName); - utils.run('git clone ' + target + ' ' + packagePath); -} - -// Remove any existing node_modules in the extension. -if (fs.existsSync(path.join(packagePath, 'node_modules'))) { - fs.removeSync(path.join(packagePath, 'node_modules')); -} - -// Make sure composite is set to true in the new package. -const packageTsconfigPath = path.join(packagePath, 'tsconfig.json'); -if (fs.existsSync(packageTsconfigPath)) { - const packageTsconfig = utils.readJSONFile(packageTsconfigPath); - packageTsconfig.compilerOptions.composite = true; - utils.writeJSONFile(packageTsconfigPath, packageTsconfig); -} - -// Get the package.json of the extension. -const pkgJSONPath = path.join(packagePath, 'package.json'); -const data = utils.readJSONFile(pkgJSONPath); -if (data.private !== true) { - data.publishConfig = {}; - data.publishConfig.access = 'public'; - utils.writeJSONFile(pkgJSONPath, data); -} - -// Add the extension path to packages/metapackage/tsconfig.json -const tsconfigPath = path.join( - basePath, - 'packages', - 'metapackage', - 'tsconfig.json' -); -const tsconfig = utils.readJSONFile(tsconfigPath); -tsconfig.references.push({ - path: path.posix.join('..', '..', packageDirName) -}); -utils.writeJSONFile(tsconfigPath, tsconfig); - -// Update the core jupyterlab build dependencies. -utils.run('jlpm run integrity'); diff --git a/buildutils/src/bump-js-major.ts b/buildutils/src/bump-js-major.ts index 656a582337e2..fe70bac9bf7b 100644 --- a/buildutils/src/bump-js-major.ts +++ b/buildutils/src/bump-js-major.ts @@ -3,7 +3,7 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -import commander from 'commander'; +import { program as commander } from 'commander'; import semver from 'semver'; import path from 'path'; import * as utils from './utils'; @@ -36,7 +36,7 @@ commander .option('--force', 'Force the upgrade') .option('--dry-run', 'Show what would be executed') .action((pkg: string, others: Array, options: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); others.push(pkg); const toBump: Set = new Set(); const ignoreBump: Set = new Set(); @@ -65,7 +65,7 @@ commander }); // Look for dependencies of bumped packages - Array.from(toBump).forEach(val => { + toBump.forEach(val => { const deps = getDeps(val, lut); deps.forEach(dep => { maybeBump(dep); diff --git a/buildutils/src/bumpversion.ts b/buildutils/src/bumpversion.ts index ed9dbee6076b..18164c815e9f 100644 --- a/buildutils/src/bumpversion.ts +++ b/buildutils/src/bumpversion.ts @@ -3,7 +3,7 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -import commander from 'commander'; +import { program as commander } from 'commander'; import * as utils from './utils'; // Specify the program signature. @@ -14,7 +14,7 @@ commander .option('--skip-commit', 'Whether to skip commit changes') .arguments('') .action((spec: any, opts: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); // Get the previous version. const prev = utils.getPythonVersion(); @@ -58,19 +58,7 @@ commander // Handle dry runs. if (opts.dryRun) { - utils.run(`bumpversion --dry-run --verbose ${spec}`); - return; - } - - // If this is a major release during the alpha cycle, bump - // just the Python version. - if (prev.indexOf('a') !== -1 && spec === 'major') { - // Bump the version. - utils.run(`bumpversion ${spec}`); - - // Run the post-bump script. - utils.postbump(commit); - + utils.run(`bumpversion --allow-dirty --dry-run --verbose ${spec}`); return; } @@ -92,22 +80,17 @@ commander lernaVersion += ' --preid=alpha'; } - let cmd = `lerna version -m \"[ci skip] New version\" --force-publish=* --no-push ${lernaVersion}`; + let cmd = `lerna version --no-git-tag-version --force-publish=* --no-push ${lernaVersion}`; if (opts.force) { cmd += ' --yes'; } - const oldVersion = utils.run( - 'git rev-parse HEAD', - { - stdio: 'pipe', - encoding: 'utf8' - }, - true - ); - // For a preminor release, we bump 10 minor versions so that we do + + const oldVersion = utils.getJSVersion('metapackage'); + + // For a major release, we bump 10 minor versions so that we do // not conflict with versions during minor releases of the top // level package. - if (lernaVersion === 'preminor') { + if (spec === 'major') { for (let i = 0; i < 10; i++) { utils.run(cmd); } @@ -115,21 +98,14 @@ commander utils.run(cmd); } - const newVersion = utils.run( - 'git rev-parse HEAD', - { - stdio: 'pipe', - encoding: 'utf8' - }, - true - ); - if (oldVersion === newVersion) { + const newVersion = utils.getJSVersion('metapackage'); + if (spec !== 'major' && oldVersion === newVersion) { // lerna didn't version anything, so we assume the user aborted throw new Error('Lerna aborted'); } // Bump the version. - utils.run(`bumpversion ${spec}`); + utils.run(`bumpversion --allow-dirty ${spec}`); // Run the post-bump script. utils.postbump(commit); diff --git a/buildutils/src/clean-packages.ts b/buildutils/src/clean-packages.ts index 27cf480cbac2..026f927c9389 100644 --- a/buildutils/src/clean-packages.ts +++ b/buildutils/src/clean-packages.ts @@ -6,9 +6,9 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import * as glob from 'glob'; -import { exitOnUuncaughtException, readJSONFile } from './utils'; +import { exitOnUncaughtException, readJSONFile } from './utils'; -exitOnUuncaughtException(); +exitOnUncaughtException(); // Get all of the packages. const basePath = path.resolve('.'); diff --git a/buildutils/src/create-package.ts b/buildutils/src/create-package.ts index 264460a3f3cb..0fd78080f45e 100644 --- a/buildutils/src/create-package.ts +++ b/buildutils/src/create-package.ts @@ -4,11 +4,10 @@ |----------------------------------------------------------------------------*/ import * as fs from 'fs-extra'; -import * as inquirer from 'inquirer'; import * as path from 'path'; import * as utils from './utils'; -const questions: inquirer.Question[] = [ +const questions = [ { type: 'input', name: 'name', @@ -21,27 +20,30 @@ const questions: inquirer.Question[] = [ } ]; -void inquirer.prompt(questions).then(answers => { - let { name, description } = answers; - const dest = path.resolve(path.join('.', 'packages', name)); - if (fs.existsSync(dest)) { - console.error('Package already exists: ', name); - process.exit(1); - } - fs.copySync(path.resolve(path.join(__dirname, '..', 'template')), dest); - const jsonPath = path.join(dest, 'package.json'); - const data = utils.readJSONFile(jsonPath); - if (name.indexOf('@jupyterlab/') === -1) { - name = '@jupyterlab/' + name; - } - data.name = name; - data.description = description; - utils.writePackageData(jsonPath, data); +void import('inquirer') + .then(inquirer => inquirer.createPromptModule()) + .then(prompt => prompt(questions)) + .then(answers => { + let { name, description } = answers; + const dest = path.resolve(path.join('.', 'packages', name)); + if (fs.existsSync(dest)) { + console.error('Package already exists: ', name); + process.exit(1); + } + fs.copySync(path.resolve(path.join(__dirname, '..', 'template')), dest); + const jsonPath = path.join(dest, 'package.json'); + const data = utils.readJSONFile(jsonPath); + if (name.indexOf('@jupyterlab/') === -1) { + name = '@jupyterlab/' + name; + } + data.name = name; + data.description = description; + utils.writePackageData(jsonPath, data); - // Add the launch file to git. - const launch = path.join(dest, '.vscode', 'launch.json'); - utils.run(`git add -f ${launch}`); + // Add the launch file to git. + const launch = path.join(dest, '.vscode', 'launch.json'); + utils.run(`git add -f ${launch}`); - // Use npm here so this file can be used outside of JupyterLab. - utils.run('npm run integrity'); -}); + // Use npm here so this file can be used outside of JupyterLab. + utils.run('npm run integrity'); + }); diff --git a/buildutils/src/create-theme.ts b/buildutils/src/create-theme.ts deleted file mode 100644 index c27829c32eff..000000000000 --- a/buildutils/src/create-theme.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* ----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ - -import * as fs from 'fs-extra'; -import * as inquirer from 'inquirer'; -import * as path from 'path'; -import * as utils from './utils'; - -const questions: inquirer.Question[] = [ - { - type: 'input', - name: 'name', - message: 'name: ' - }, - { - type: 'input', - name: 'title', - message: 'title: ' - }, - { - type: 'input', - name: 'description', - message: 'description: ' - } -]; - -const template = ` -import { - JupyterFrontEnd, JupyterFrontEndPlugin -} from '@jupyterlab/application'; - -import { - IThemeManager -} from '@jupyterlab/apputils'; - - -/** - * A plugin for the {{title}} - */ -const plugin: JupyterFrontEndPlugin = { - id: '{{name}}:plugin', - requires: [IThemeManager], - activate: (app: JupyterFrontEnd, manager: IThemeManager) => { - manager.register({ - name: '{{title}}', - isLight: true, - load: () => manager.loadCSS('{{name}}/index.css'), - unload: () => Promise.resolve(undefined) - }); - }, - autoStart: true -}; - - -export default plugin; -`; - -void inquirer.prompt(questions).then(answers => { - const { name, title, description } = answers; - const dest = path.resolve(path.join('.', name)); - if (fs.existsSync(dest)) { - console.error('Package already exists: ', name); - process.exit(1); - } - fs.copySync(path.resolve('.', 'packages', 'theme-light-extension'), dest); - const jsonPath = path.join(dest, 'package.json'); - const data = utils.readJSONFile(jsonPath); - data.name = name; - data.description = description; - utils.writePackageData(jsonPath, data); - - // update the urls in urls.css - const filePath = path.resolve('.', name, 'style', 'urls.css'); - let text = fs.readFileSync(filePath, 'utf8'); - text = text.split('@jupyterlab/theme-light-extension').join(name); - fs.writeFileSync(filePath, text, 'utf8'); - - // remove lib, node_modules and static. - ['lib', 'node_modules', 'static'].forEach(folder => { - const folderPath = path.join('.', name, folder); - if (fs.existsSync(folderPath)) { - fs.removeSync(folderPath); - } - }); - - const readme = `${name}\n${description}\n`; - fs.writeFileSync(path.join('.', name, 'README.md'), readme, 'utf8'); - - let src = template.split('{{name}}').join(name); - src = src.split('{{title}}').join(title); - fs.writeFileSync(path.join('.', name, 'src', 'index.ts'), src, 'utf8'); - - // Signify successful complation. - console.debug(`Created new theme ${name}`); -}); diff --git a/buildutils/src/dependency-graph.ts b/buildutils/src/dependency-graph.ts deleted file mode 100644 index 97c222042da1..000000000000 --- a/buildutils/src/dependency-graph.ts +++ /dev/null @@ -1,294 +0,0 @@ -/* ----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ - -import * as fs from 'fs-extra'; -import * as lockfile from '@yarnpkg/lockfile'; -import * as path from 'path'; -import * as utils from './utils'; -import commander from 'commander'; - -/** - * Flatten a nested array one level. - */ -function flat(arr: any[]) { - return arr.reduce((acc, val) => acc.concat(val), []); -} - -/** - * Parse the yarn file at the given path. - */ -function readYarn(basePath: string = '.') { - const file = fs.readFileSync(path.join(basePath, 'yarn.lock'), 'utf8'); - const json = lockfile.parse(file); - - if (json.type !== 'success') { - throw new Error('Error reading file'); - } - - return json.object; -} - -/** - * Get a node name corresponding to package@versionspec. - * - * The nodes names are of the form "@". - * - * Returns undefined if the package is not fund - */ -function getNode(yarnData: any, pkgName: string) { - if (!(pkgName in yarnData)) { - console.error( - `Could not find ${pkgName} in yarn.lock file. Ignore if this is a top-level package.` - ); - return undefined; - } - const name = pkgName[0] + pkgName.slice(1).split('@')[0]; - const version = yarnData[pkgName].version; - const pkgNode = `${name}@${version}`; - return pkgNode; -} - -/** - * The type for graphs. - * - * Keys are nodes, values are the list of neighbors for the node. - */ -type Graph = { [key: string]: string[] }; - -/** - * Build a dependency graph based on the yarn data. - */ -function buildYarnGraph(yarnData: any): Graph { - // 'a': ['b', 'c'] means 'a' depends on 'b' and 'c' - const dependsOn: Graph = Object.create(null); - - Object.keys(yarnData).forEach(pkgName => { - const pkg = yarnData[pkgName]; - const pkgNode = getNode(yarnData, pkgName)!; - - // If multiple version specs resolve to the same actual package version, we - // only want to record the dependency once. - if (dependsOn[pkgNode] !== undefined) { - return; - } - - dependsOn[pkgNode] = []; - const deps = pkg.dependencies; - if (deps) { - Object.keys(deps).forEach(depName => { - const depNode = getNode(yarnData, `${depName}@${deps[depName]}`)!; - dependsOn[pkgNode].push(depNode); - }); - } - }); - return dependsOn; -} - -/** - * Construct a subgraph of all nodes reachable from the given nodes. - */ -function subgraph(graph: Graph, nodes: string[]): Graph { - const sub = Object.create(null); - // Seed the graph - let newNodes = nodes; - while (newNodes.length > 0) { - const old = newNodes; - newNodes = []; - old.forEach(i => { - if (!(i in sub)) { - sub[i] = graph[i]; - newNodes.push(...sub[i]); - } - }); - } - return sub; -} - -/** - * Return the package.json data at the given path - */ -function pkgData(packagePath: string) { - packagePath = path.join(packagePath, 'package.json'); - let data: any; - try { - data = utils.readJSONFile(packagePath); - } catch (e) { - console.error('Skipping package ' + packagePath); - return {}; - } - return data; -} - -function convertDot( - g: { [key: string]: string[] }, - graphOptions: string, - distinguishRoots = false, - distinguishLeaves = false -) { - const edges: string[][] = flat( - Object.keys(g).map(a => g[a].map(b => [a, b])) - ).sort(); - const nodes = Object.keys(g).sort(); - // let leaves = Object.keys(g).filter(i => g[i].length === 0); - // let roots = Object.keys(g).filter(i => g[i].length === 0); - const dot = ` -digraph DEPS { - ${graphOptions || ''} - ${nodes.map(node => `"${node}";`).join(' ')} - ${edges.map(([a, b]) => `"${a}" -> "${b}"`).join('\n ')} -} -`; - return dot; -} - -interface IMainOptions { - dependencies: boolean; - devDependencies: boolean; - jupyterlab: boolean; - lerna: boolean; - lernaExclude: string; - lernaInclude: string; - path: string; - lumino: boolean; - topLevel: boolean; -} - -function main({ - dependencies, - devDependencies, - jupyterlab, - lerna, - lernaExclude, - lernaInclude, - path, - lumino, - topLevel -}: IMainOptions) { - const yarnData = readYarn(path); - const graph = buildYarnGraph(yarnData); - - const paths: string[] = [path]; - if (lerna !== false) { - paths.push(...utils.getLernaPaths(path).sort()); - } - - // Get all package data - let data: any[] = paths.map(p => pkgData(p)); - - // Get top-level package names (these won't be listed in yarn) - const topLevelNames: Set = new Set(data.map(d => d.name)); - - // Filter lerna packages if a regex was supplied - if (lernaInclude) { - const re = new RegExp(lernaInclude); - data = data.filter(d => d.name && d.name.match(re)); - } - if (lernaExclude) { - const re = new RegExp(lernaExclude); - data = data.filter(d => d.name && !d.name.match(re)); - } - - const depKinds: string[] = []; - if (devDependencies) { - depKinds.push('devDependencies'); - } - if (dependencies) { - depKinds.push('dependencies'); - } - /** - * All dependency roots *except* other packages in this repo. - */ - const dependencyRoots: string[][] = data.map(d => { - const roots: string[] = []; - for (const depKind of depKinds) { - const deps = d[depKind]; - if (deps === undefined) { - continue; - } - const nodes = Object.keys(deps) - .map(i => { - // Do not get a package if it is a top-level package (and this is - // not in yarn). - if (!topLevelNames.has(i)) { - return getNode(yarnData, `${i}@${deps[i]}`); - } - }) - .filter(i => i !== undefined) as string[]; - roots.push(...nodes); - } - return roots; - }); - - // Find the subgraph - const sub = subgraph(graph, flat(dependencyRoots)); - - // Add in top-level lerna packages if desired - if (topLevel) { - data.forEach((d, i) => { - sub[`${d.name}@${d.version}`] = dependencyRoots[i]; - }); - } - - // Filter out *all* lumino nodes - if (!lumino) { - Object.keys(sub).forEach(v => { - sub[v] = sub[v].filter(w => !w.startsWith('@lumino/')); - }); - Object.keys(sub).forEach(v => { - if (v.startsWith('@lumino/')) { - delete sub[v]; - } - }); - } - - // Filter for any edges going into a jlab package, and then for any - // disconnected jlab packages. This preserves jlab packages in the graph that - // point to other packages, so we can see where third-party packages come - // from. - if (!jupyterlab) { - Object.keys(sub).forEach(v => { - sub[v] = sub[v].filter(w => !w.startsWith('@jupyterlab/')); - }); - Object.keys(sub).forEach(v => { - if (v.startsWith('@jupyterlab/') && sub[v].length === 0) { - delete sub[v]; - } - }); - } - - return sub; -} - -commander - .description(`Print out the dependency graph in dot graph format.`) - .option('--lerna', 'Include dependencies in all lerna packages') - .option( - '--lerna-include ', - 'A regex for package names to include in dependency roots' - ) - .option( - '--lerna-exclude ', - 'A regex for lerna package names to exclude from dependency roots (can override the include regex)' - ) - .option('--path [path]', 'Path to package or monorepo to investigate', '.') - .option( - '--no-jupyterlab', - 'Do not include dependency connections TO @jupyterlab org packages nor isolated @jupyterlab org packages' - ) - .option('--no-lumino', 'Do not include @lumino org packages') - .option('--no-devDependencies', 'Do not include dev dependencies') - .option('--no-dependencies', 'Do not include normal dependencies') - .option('--no-top-level', 'Do not include the top-level packages') - .option( - '--graph-options ', - 'dot graph options (such as "ratio=0.25; concentrate=true;")' - ) - .action(args => { - const graph = main(args); - console.debug(convertDot(graph, args.graphOptions)); - console.error(`Nodes: ${Object.keys(graph).length}`); - }); - -commander.parse(process.argv); diff --git a/buildutils/src/ensure-package.ts b/buildutils/src/ensure-package.ts index 5a2226753253..0522ff52fb00 100644 --- a/buildutils/src/ensure-package.ts +++ b/buildutils/src/ensure-package.ts @@ -68,8 +68,13 @@ export async function ensurePackage( const cssImports = options.cssImports || []; const cssModuleImports = options.cssModuleImports || []; const differentVersions = options.differentVersions || []; + const backwardVersions = options.backwardVersions ?? {}; const isPrivate = data.private == true; + const hasBackwardCompatibilities = Object.keys(backwardVersions).includes( + data.name + ); + // Verify dependencies are consistent. let promises = Object.keys(deps).map(async name => { if (differentVersions.indexOf(name) !== -1) { @@ -80,9 +85,50 @@ export async function ensurePackage( seenDeps[name] = await getDependency(name); } if (deps[name] !== seenDeps[name]) { - messages.push(`Updated dependency: ${name}@${seenDeps[name]}`); + const oneOf = + deps[name].includes('||') && + deps[name] + .split(/\|\|/) + .map(v => v.trim()) + .includes(seenDeps[name]); + + if (!oneOf) { + if ( + hasBackwardCompatibilities && + Object.keys(backwardVersions[data.name]).includes(name) + ) { + messages.push( + `Updated dependency: ${name}@${ + backwardVersions[data.name][name] + } || ${seenDeps[name]}` + ); + deps[name] = `${backwardVersions[data.name][name]} || ${ + seenDeps[name] + }`; + } else { + messages.push(`Updated dependency: ${name}@${seenDeps[name]}`); + deps[name] = seenDeps[name]; + } + } + } + + if ( + hasBackwardCompatibilities && + Object.keys(backwardVersions[data.name]).includes(name) + ) { + const oneOf = deps[name] + .split(/\|\|/) + .map(v => v.trim()) + .includes(backwardVersions[data.name][name]); + if (!oneOf) { + messages.push( + `Updated backward dependency: ${name}@${ + backwardVersions[data.name][name] + } || ${deps[name]}` + ); + deps[name] = `${backwardVersions[data.name][name]} || ${deps[name]}`; + } } - deps[name] = seenDeps[name]; }); await Promise.all(promises); @@ -140,23 +186,29 @@ export async function ensurePackage( data.name !== '@jupyterlab/codemirror' ) { imports.forEach(importStr => { - if (importStr.indexOf('.css') !== -1) { - messages.push('CSS imports are not allowed source files'); + if ( + importStr.indexOf('.css') !== -1 && + importStr.indexOf('.raw.css') === -1 + ) { + messages.push( + 'CSS imports are not allowed source files unless using `.raw.css` extension' + ); } }); } - let names: string[] = Array.from(new Set(imports)).sort(); - names = names.map(function (name) { - const parts = name.split('/'); - if (name.indexOf('@') === 0) { - return parts[0] + '/' + parts[1]; - } - if (parts[0].indexOf('!') !== -1) { - parts[0] = parts[0].slice(parts[0].lastIndexOf('!') + 1); - } - return parts[0]; - }); + const names = Array.from(new Set(imports)) + .sort() + .map(name => { + const parts = name.split('/'); + if (name.indexOf('@') === 0) { + return parts[0] + '/' + parts[1]; + } + if (parts[0].indexOf('!') !== -1) { + parts[0] = parts[0].slice(parts[0].lastIndexOf('!') + 1); + } + return parts[0]; + }); // Look for imports with no dependencies. promises = names.map(async name => { @@ -187,12 +239,13 @@ export async function ensurePackage( // Template the CSS index file. const cssIndexContents = [ utils.fromTemplate(HEADER_TEMPLATE, { funcName }, { end: '' }), - ...cssImports.map(x => `@import url('~${x}');`), - '' + ...cssImports.map(x => `@import url('~${x}');`) ]; if (fs.existsSync(path.join(pkgPath, 'style/base.css'))) { - cssIndexContents.push("@import url('./base.css');\n"); + cssIndexContents.push("@import url('./base.css');"); } + // Add final line return + cssIndexContents.push(''); // write out cssIndexContents, if needed const cssIndexPath = path.join(pkgPath, 'style/index.css'); @@ -200,7 +253,7 @@ export async function ensurePackage( fs.ensureFileSync(cssIndexPath); } messages.push( - ...ensureFile(cssIndexPath, cssIndexContents.join('\n'), false) + ...(await ensureFile(cssIndexPath, cssIndexContents.join('\n'), false)) ); // Template the style module index file. @@ -219,7 +272,7 @@ export async function ensurePackage( fs.ensureFileSync(jsIndexPath); } messages.push( - ...ensureFile(jsIndexPath, jsIndexContents.join('\n'), false) + ...(await ensureFile(jsIndexPath, jsIndexContents.join('\n'), false)) ); } else { if ( @@ -242,7 +295,7 @@ export async function ensurePackage( } const isTest = data.name.indexOf('test') !== -1; if (isTest) { - const testLibs = ['jest', 'ts-jest', '@jupyterlab/testutils']; + const testLibs = ['jest', 'ts-jest', '@jupyterlab/testing']; if (testLibs.indexOf(name) !== -1) { return; } @@ -334,9 +387,6 @@ export async function ensurePackage( Object.keys(testReferences).forEach(name => { tsConfigTestData.references.push({ path: testReferences[name] }); }); - Object.keys(references).forEach(name => { - tsConfigTestData.references.push({ path: testReferences[name] }); - }); utils.writeJSONFile(tsConfigTestPath, tsConfigTestData); } @@ -465,13 +515,21 @@ export async function ensurePackage( // Ensure style and lib are included in files metadata. const filePatterns: string[] = data.files || []; + const ignoreDirs: string[] = ['.ipynb_checkpoints']; // Function to get all of the files in a directory, recursively. - function recurseDir(dirname: string, files: string[]) { + function recurseDir( + dirname: string, + files: string[], + skipDirs: string[] = ignoreDirs + ) { if (!fs.existsSync(dirname)) { return files; } fs.readdirSync(dirname).forEach(fpath => { + if (skipDirs.includes(fpath)) { + return files; + } const absolute = path.join(dirname, fpath); if (fs.statSync(absolute).isDirectory()) return recurseDir(absolute, files); @@ -480,40 +538,75 @@ export async function ensurePackage( return files; } - // Ensure style files are included by pattern. - const styleFiles = recurseDir(path.join(pkgPath, 'style'), []); - styleFiles.forEach(fpath => { - const basePath = fpath.slice(pkgPath.length + 1); - let found = false; - filePatterns.forEach(fpattern => { - if (minimatch.default(basePath, fpattern)) { - found = true; + if (!isPrivate) { + // Ensure style files are included by pattern. + const styleFiles = recurseDir(path.join(pkgPath, 'style'), []); + styleFiles.forEach(fpath => { + const basePath = fpath.slice(pkgPath.length + 1); + let found = false; + filePatterns.forEach(fpattern => { + if (minimatch.default(basePath, fpattern)) { + found = true; + } + }); + if (!found) { + messages.push(`File ${basePath} not included in files`); } }); - if (!found && !isPrivate) { - messages.push(`File ${basePath} not included in files`); - } - }); - // Ensure source TS files are included in lib (.js, .js.map, .d.ts) - const srcFiles = recurseDir(path.join(pkgPath, 'src'), []); - srcFiles.forEach(fpath => { - const basePath = fpath.slice(pkgPath.length + 1).replace('src', 'lib'); - ['.js', '.js.map', '.d.ts'].forEach(ending => { + // Ensure source TS files are included in lib (.js, .js.map, .d.ts) + const srcFiles = recurseDir(path.join(pkgPath, 'src'), []); + srcFiles.forEach(fpath => { + const basePath = fpath + .slice(pkgPath.length + 1) + .replace('src', 'lib') + .split(path.sep) + .join('/'); + ['.js', '.js.map', '.d.ts'].forEach(ending => { + let found = false; + const targetPattern = basePath.replace(/\.tsx?$/g, ending); + filePatterns.forEach(fpattern => { + if (minimatch.default(targetPattern, fpattern)) { + found = true; + } + }); + if (!found) { + messages.push(`File ${targetPattern} not included in files`); + } + }); + }); + + // Ensure source files are all included + let anySourceMatch = false; + const missingSourceMessages: string[] = []; + srcFiles.forEach(fpath => { + const basepath = fpath + .slice(pkgPath.length + 1) + .split(path.sep) + .join('/'); let found = false; - const targetPattern = basePath - .replace('.tsx', ending) - .replace('.ts', ending); filePatterns.forEach(fpattern => { - if (minimatch.default(targetPattern, fpattern)) { + if (minimatch.default(basepath, fpattern)) { found = true; } }); - if (!found && !isPrivate) { - messages.push(`File ${targetPattern} not included in files`); + anySourceMatch = anySourceMatch || found; + if (!found) { + missingSourceMessages.push( + `Source file ${basepath} not included in files` + ); } }); - }); + if (srcFiles.length && !anySourceMatch) { + messages.push('Found no src file inclusion, adding src/**/*.{ts,tsx}'); + if (!data.files) { + data.files = []; + } + data.files.push('src/**/*.{ts,tsx}'); + } else { + messages.push(...missingSourceMessages); + } + } // Ensure dependencies and dev dependencies. data.dependencies = deps; @@ -542,12 +635,12 @@ export async function ensurePackage( delete data.scripts.prepublishOnly; } - // If the package is not in `packages` or does not use `tsc` in its + // If the package does not use `tsc` in its // build script, add a `build:all` target const buildScript = data.scripts?.build || ''; if ( - buildScript && - (pkgPath.indexOf('packages') == -1 || buildScript.indexOf('tsc') == -1) && + path.basename(pkgPath) != 'galata' && + buildScript?.indexOf('tsc') === -1 && !isPrivate ) { data.scripts['build:all'] = 'npm run build'; @@ -665,7 +758,9 @@ export async function ensureUiComponents( HEADER_TEMPLATE + ICON_IMPORTS_TEMPLATE, { funcName, svgImportStatements, labiconConstructions } ); - messages.push(...ensureFile(iconImportsPath, iconImportsContents, false)); + messages.push( + ...(await ensureFile(iconImportsPath, iconImportsContents, false)) + ); /* support for deprecated icon CSS classes */ const iconCSSDir = path.join(pkgPath, 'style'); @@ -691,7 +786,7 @@ export async function ensureUiComponents( // sort the statements and then join them const iconCSSUrls = _iconCSSUrls.sort().join('\n'); - const iconCSSDeclarations = _iconCSSDeclarations.sort().join('\n'); + const iconCSSDeclarations = _iconCSSDeclarations.sort().join('\n\n'); // generate the actual contents of the iconCSSClasses file const iconCSSClassesPath = path.join(iconCSSDir, 'deprecated.css'); @@ -699,7 +794,9 @@ export async function ensureUiComponents( HEADER_TEMPLATE + ICON_CSS_CLASSES_TEMPLATE, { funcName, iconCSSUrls, iconCSSDeclarations } ); - messages.push(...ensureFile(iconCSSClassesPath, iconCSSClassesContent)); + messages.push( + ...(await ensureFile(iconCSSClassesPath, iconCSSClassesContent)) + ); return messages; } @@ -757,6 +854,11 @@ export interface IEnsurePackageOptions { * Packages which are allowed to have multiple versions pulled in */ differentVersions?: string[]; + + /** + * Older versions supported by core packages in addition to the latest. + */ + backwardVersions?: Record>; } /** @@ -775,11 +877,11 @@ export interface IEnsurePackageOptions { * * @returns a string array with 0 or 1 messages. */ -function ensureFile( +async function ensureFile( fpath: string, contents: string, prettify: boolean = true -): string[] { +): Promise { const messages: string[] = []; if (!fs.existsSync(fpath)) { @@ -792,7 +894,7 @@ function ensureFile( // (maybe) run the newly generated contents through prettier before comparing let formatted = prettify - ? prettier.format(contents, { filepath: fpath, singleQuote: true }) + ? await prettier.format(contents, { filepath: fpath, singleQuote: true }) : contents; const prev = fs.readFileSync(fpath, { encoding: 'utf8' }); diff --git a/buildutils/src/ensure-repo.ts b/buildutils/src/ensure-repo.ts index e653ea852a9f..f681d609a203 100644 --- a/buildutils/src/ensure-repo.ts +++ b/buildutils/src/ensure-repo.ts @@ -24,35 +24,36 @@ import { type Dict = { [key: string]: T }; +type CoreData = Map; + // URL config for this branch // Source and target branches // Target RTD version name -// For master these will be the same, for other branches the source +// For main these will be the same, for other branches the source // branch is whichever branch it was created from // The current release branch should target RTD stable -// Master should target latest +// Main should target latest // All other release branches should target a specific named version const URL_CONFIG = { - source: '3.5.x', - target: '3.6.x', - rtdVersion: '3.6.x' + source: 'main', + target: '4.0.x', + rtdVersion: 'stable' }; // Data to ignore. const MISSING: Dict = { '@jupyterlab/coreutils': ['path'], - '@jupyterlab/buildutils': ['path', 'webpack'], - '@jupyterlab/builder': ['path', 'crypto'], - '@jupyterlab/galata': ['fs', 'path'], - '@jupyterlab/testutils': ['fs', 'path'], + '@jupyterlab/buildutils': ['assert', 'fs', 'path', 'webpack'], + '@jupyterlab/builder': ['path'], + '@jupyterlab/galata': ['fs', 'path', '@jupyterlab/galata'], + '@jupyterlab/testing': ['fs', 'path'], '@jupyterlab/vega5-extension': ['vega-embed'] }; const UNUSED: Dict = { // url is a polyfill for sanitize-html - '@jupyterlab/apputils': ['@types/react', 'url'], + '@jupyterlab/apputils': ['@types/react'], '@jupyterlab/application': ['@fortawesome/fontawesome-free'], - '@jupyterlab/apputils-extension': ['es6-promise'], '@jupyterlab/builder': [ '@lumino/algorithm', '@lumino/application', @@ -70,43 +71,69 @@ const UNUSED: Dict = { // The libraries needed for building other extensions. '@babel/core', '@babel/preset-env', - 'babel-loader', 'css-loader', - 'file-loader', 'path-browserify', 'process', - 'raw-loader', 'style-loader', - 'svg-url-loader', 'terser-webpack-plugin', - 'to-string-loader', - 'url-loader', 'webpack-cli', 'worker-loader', 'source-map-loader' ], - '@jupyterlab/buildutils': ['verdaccio'], + '@jupyterlab/buildutils': ['inquirer', 'verdaccio'], + '@jupyterlab/codemirror': [ + '@codemirror/lang-cpp', + '@codemirror/lang-css', + '@codemirror/lang-html', + '@codemirror/lang-java', + '@codemirror/lang-javascript', + '@codemirror/lang-json', + '@codemirror/lang-markdown', + '@codemirror/lang-php', + '@codemirror/lang-python', + '@codemirror/lang-rust', + '@codemirror/lang-sql', + '@codemirror/lang-wast', + '@codemirror/lang-xml', + '@codemirror/legacy-modes' + ], + '@jupyterlab/codemirror-extension': [ + '@codemirror/lang-markdown', + '@codemirror/legacy-modes' + ], '@jupyterlab/coreutils': ['path-browserify'], - '@jupyterlab/galata': ['node-fetch', 'http-server'], - '@jupyterlab/services': ['node-fetch', 'ws'], - '@jupyterlab/shared-models': ['@jupyter/ydoc', '@jupyterlab/nbformat'], - '@jupyterlab/rendermime': ['@jupyterlab/mathjax2'], - '@jupyterlab/testutils': [ + '@jupyterlab/fileeditor': ['regexp-match-indices'], + '@jupyterlab/services': ['ws'], + '@jupyterlab/testing': [ + '@babel/core', + '@babel/preset-env', + 'fs-extra', 'node-fetch', 'identity-obj-proxy', - 'jest-raw-loader', - 'markdown-loader-jest', - 'jest-junit', - 'jest-summary-reporter' + 'jest-environment-jsdom', + 'jest-junit' + ], + '@jupyterlab/testutils': [ + '@jupyterlab/application', + '@jupyterlab/apputils', + '@jupyterlab/notebook', + '@jupyterlab/rendermime' ], '@jupyterlab/test-csvviewer': ['csv-spectrum'], - '@jupyterlab/vega5-extension': ['vega', 'vega-lite'], - '@jupyterlab/ui-components': ['@blueprintjs/icons'] + '@jupyterlab/vega5-extension': ['vega', 'vega-lite'] }; // Packages that are allowed to have differing versions const DIFFERENT_VERSIONS: Array = ['vega-lite', 'vega', 'vega-embed']; +// Packages that have backward versions support +const BACKWARD_VERSIONS: Record> = { + '@jupyterlab/rendermime-interfaces': { + '@lumino/coreutils': '^1.11.0', + '@lumino/widgets': '^1.37.2' + } +}; + const SKIP_CSS: Dict = { '@jupyterlab/application': ['@jupyterlab/rendermime'], '@jupyterlab/application-extension': ['@jupyterlab/apputils'], @@ -124,9 +151,7 @@ const SKIP_CSS: Dict = { '@lumino/virtualdom', '@lumino/widgets' ], - '@jupyterlab/codemirror-extension': ['codemirror'], '@jupyterlab/completer': ['@jupyterlab/codeeditor'], - '@jupyterlab/debugger': ['codemirror'], '@jupyterlab/docmanager': ['@jupyterlab/statusbar'], // Statusbar styles should not be used by status reporters '@jupyterlab/docregistry': [ '@jupyterlab/codeeditor', // Only used for model @@ -138,12 +163,27 @@ const SKIP_CSS: Dict = { '@jupyterlab/codeeditor', '@jupyterlab/codemirror', '@jupyterlab/fileeditor', - '@jupyterlab/notebook', - 'codemirror' + '@jupyterlab/notebook' ], '@jupyterlab/filebrowser': ['@jupyterlab/statusbar'], '@jupyterlab/fileeditor': ['@jupyterlab/statusbar'], + '@jupyterlab/galata': [ + '@jupyterlab/application', + '@jupyterlab/apputils', + '@jupyterlab/debugger', + '@jupyterlab/docmanager', + '@jupyterlab/notebook' + ], + '@jupyterlab/galata-extension': [ + '@jupyterlab/application', + '@jupyterlab/apputils', + '@jupyterlab/cells', + '@jupyterlab/debugger', + '@jupyterlab/docmanager', + '@jupyterlab/notebook' + ], '@jupyterlab/help-extension': ['@jupyterlab/application'], + '@jupyterlab/lsp': ['codemirror'], '@jupyterlab/metapackage': [ '@jupyterlab/ui-components', '@jupyterlab/apputils', @@ -166,7 +206,6 @@ const SKIP_CSS: Dict = { '@jupyterlab/notebook', '@jupyterlab/cell-toolbar', '@jupyterlab/cell-toolbar-extension', - '@jupyterlab/celltags', '@jupyterlab/celltags-extension', '@jupyterlab/fileeditor', '@jupyterlab/codemirror-extension', @@ -177,12 +216,10 @@ const SKIP_CSS: Dict = { '@jupyterlab/console-extension', '@jupyterlab/csvviewer', '@jupyterlab/documentsearch', - '@jupyterlab/docprovider', '@jupyterlab/csvviewer-extension', '@jupyterlab/debugger', '@jupyterlab/debugger-extension', '@jupyterlab/docmanager-extension', - '@jupyterlab/docprovider-extension', '@jupyterlab/documentsearch-extension', '@jupyterlab/extensionmanager', '@jupyterlab/extensionmanager-extension', @@ -201,11 +238,15 @@ const SKIP_CSS: Dict = { '@jupyterlab/launcher-extension', '@jupyterlab/logconsole', '@jupyterlab/logconsole-extension', + '@jupyterlab/lsp', + '@jupyterlab/lsp-extension', '@jupyterlab/mainmenu-extension', '@jupyterlab/markdownviewer', '@jupyterlab/markdownviewer-extension', - '@jupyterlab/mathjax2', - '@jupyterlab/mathjax2-extension', + '@jupyterlab/markedparser-extension', + '@jupyterlab/mathjax-extension', + '@jupyterlab/metadataform', + '@jupyterlab/metadataform-extension', '@jupyterlab/nbconvert-css', '@jupyterlab/notebook-extension', '@jupyterlab/pdf-extension', @@ -226,22 +267,17 @@ const SKIP_CSS: Dict = { '@jupyterlab/tooltip-extension', '@jupyterlab/translation-extension', '@jupyterlab/ui-components-extension', - '@jupyterlab/collaboration', - '@jupyterlab/collaboration-extension', - '@jupyterlab/vdom', - '@jupyterlab/vdom-extension', '@jupyterlab/vega5-extension' ], + '@jupyterlab/notebook': ['@jupyterlab/application'], '@jupyterlab/rendermime-interfaces': ['@lumino/widgets'], '@jupyterlab/shortcuts-extension': ['@jupyterlab/application'], '@jupyterlab/testutils': [ + '@jupyterlab/application', '@jupyterlab/apputils', - '@jupyterlab/codeeditor', - '@jupyterlab/codemirror', + '@jupyterlab/notebook', '@jupyterlab/rendermime', - '@jupyterlab/docregistry', - '@jupyterlab/cells', - '@jupyterlab/notebook' + '@jupyterlab/testing' ], '@jupyterlab/theme-light-extension': [ '@jupyterlab/application', @@ -250,8 +286,7 @@ const SKIP_CSS: Dict = { '@jupyterlab/theme-dark-extension': [ '@jupyterlab/application', '@jupyterlab/apputils' - ], - '@jupyterlab/ui-extension': ['@blueprintjs/icons'] + ] }; const pkgData: Dict = {}; @@ -291,7 +326,10 @@ function ensureBranch(): string[] { .trim() .split(/\r?\n/); files = files.filter(filePath => { - return fileTypes.indexOf(path.extname(filePath)) !== -1; + return ( + fileTypes.indexOf(path.extname(filePath)) !== -1 && + !filePath.endsWith('_static/switcher.json') + ); }); // Set up string replacements @@ -377,7 +415,7 @@ function ensureMetaPackage(): string[] { let valid = true; // Ensure it is a dependency. - if (!mpData.dependencies[name]) { + if (!mpData.dependencies[name] && name !== '@jupyterlab/testing') { valid = false; mpData.dependencies[name] = '^' + data.version; } @@ -410,27 +448,37 @@ function ensureMetaPackage(): string[] { } /** - * Ensure the jupyterlab application package. + * Get the core data for the given core paths. */ -function ensureJupyterlab(): string[] { - const basePath = path.resolve('.'); - const corePath = path.join(basePath, 'dev_mode', 'package.json'); - const corePackage = utils.readJSONFile(corePath); +function getCoreData(corePaths: string[]): CoreData { + const coreData = new Map(); + corePaths.forEach(pkgPath => { + const dataPath = path.join(pkgPath, 'package.json'); + let data: any; + try { + data = utils.readJSONFile(dataPath); + } catch (e) { + return; + } + + coreData.set(data.name, data); + }); + + return coreData; +} + +/** + * Ensure a core package. + */ +function ensureCorePackage(corePackage: any, corePaths: string[]) { corePackage.jupyterlab.extensions = {}; - corePackage.jupyterlab.mimeExtensions = {}; - corePackage.jupyterlab.linkedPackages = {}; - // start with known external dependencies - corePackage.dependencies = Object.assign( - {}, - corePackage.jupyterlab.externalExtensions - ); - corePackage.resolutions = {}; + corePackage.dependencies = {}; const singletonPackages: string[] = corePackage.jupyterlab.singletonPackages; - const coreData = new Map(); + const coreData = getCoreData(corePaths); - utils.getCorePaths().forEach(pkgPath => { + corePaths.forEach(pkgPath => { const dataPath = path.join(pkgPath, 'package.json'); let data: any; try { @@ -439,8 +487,6 @@ function ensureJupyterlab(): string[] { return; } - coreData.set(data.name, data); - // If the package has a tokens.ts file, make sure it is noted as a singleton if ( fs.existsSync(path.join(pkgPath, 'src', 'tokens.ts')) && @@ -486,7 +532,69 @@ function ensureJupyterlab(): string[] { )}` ); } +} + +/** + * Ensure the federated example core package. + */ +function ensureFederatedExample(): string[] { + const basePath = path.resolve('.'); + const corePath = path.join( + basePath, + 'examples', + 'federated', + 'core_package', + 'package.json' + ); + const corePackage = utils.readJSONFile(corePath); + // the list of dependencies might differ from the main JupyterLab application + const dependencies = new Set(Object.keys(corePackage.dependencies)); + + const corePaths = utils.getCorePaths().filter(p => { + return dependencies.has(`@jupyterlab/${path.basename(p)}`); + }); + + ensureCorePackage(corePackage, corePaths); + const coreData = getCoreData(corePaths); + corePackage.jupyterlab.extensions = []; + coreData.forEach((data, name) => { + // Make sure it is included as a dependency. + corePackage.dependencies[data.name] = `^${data.version}`; + + const meta = data.jupyterlab; + const keep = meta?.extension || meta?.mimeExtension; + if (!keep) { + return; + } + corePackage.jupyterlab.extensions.push(name); + }); + + corePackage.jupyterlab.extensions.sort(); + + // Write the package.json back to disk. + if (utils.writePackageData(corePath, corePackage)) { + return ['Updated federated example']; + } + return []; +} + +/** + * Ensure the jupyterlab application package. + */ +function ensureJupyterlab(): string[] { + const basePath = path.resolve('.'); + const corePath = path.join(basePath, 'dev_mode', 'package.json'); + const corePackage = utils.readJSONFile(corePath); + const corePaths = utils.getCorePaths(); + + ensureCorePackage( + corePackage, + corePaths.filter(p => !/\/packages\/testing$/.test(p)) + ); + corePackage.jupyterlab.mimeExtensions = {}; + + const coreData = getCoreData(corePaths); coreData.forEach((data, name) => { // Determine if the package wishes to be included in the top-level // dependencies. @@ -504,7 +612,7 @@ function ensureJupyterlab(): string[] { // Handle extensions. ['extension', 'mimeExtension'].forEach(item => { - let ext = meta[item]; + let ext = data.jupyterlab[item]; if (ext === true) { ext = ''; } @@ -515,6 +623,7 @@ function ensureJupyterlab(): string[] { }); }); + corePackage.jupyterlab.linkedPackages = {}; utils.getLernaPaths().forEach(pkgPath => { const dataPath = path.join(pkgPath, 'package.json'); let data: any; @@ -535,6 +644,10 @@ function ensureJupyterlab(): string[] { corePackage.jupyterlab.linkedPackages[data.name] = relativePath; }); + // Update the dev mode version. + const curr = utils.getPythonVersion(); + corePackage.jupyterlab.version = curr; + // Write the package.json back to disk. if (utils.writePackageData(corePath, corePackage)) { return ['Updated dev mode']; @@ -565,36 +678,6 @@ function ensureBuildUtils() { }); } -/** - * Ensure lockfile structure - */ -function ensureLockfile(): string[] { - const staging = './jupyterlab/staging'; - const lockFile = path.join(staging, 'yarn.lock'); - const content = fs.readFileSync(lockFile, { encoding: 'utf-8' }); - let newContent = content; - const messages = []; - - // Verify that all packages have resolved to the correct (default) registry - const resolvedPattern = /^\s*resolved "((?!https:\/\/registry\.yarnpkg\.com\/).*)"\s*$/gm; - let badRegistry; - while ((badRegistry = resolvedPattern.exec(content)) !== null) { - messages.push(`Fixing bad npm/yarn registry: ${badRegistry[1]}`); - const parsed = new URL(badRegistry[1]); - const newUrl = badRegistry[1].replace( - parsed.origin, - 'https://registry.yarnpkg.com' - ); - newContent = newContent.replace(badRegistry[1], newUrl); - } - - if (content !== newContent) { - // Write the updated lockfile data back - fs.writeFileSync(lockFile, newContent, 'utf-8'); - } - return messages; -} - /** * Ensure the repo integrity. */ @@ -721,7 +804,8 @@ export async function ensureIntegrity(): Promise { locals, cssImports: cssImports[name], cssModuleImports: cssModuleImports[name], - differentVersions: DIFFERENT_VERSIONS + differentVersions: DIFFERENT_VERSIONS, + backwardVersions: BACKWARD_VERSIONS }; if (name === '@jupyterlab/metapackage') { @@ -744,12 +828,6 @@ export async function ensureIntegrity(): Promise { messages[pkgName] = messages[pkgName].concat(pkgMessages); } - // Ensure the staging area lockfile - const lockFileMessages = ensureLockfile(); - if (lockFileMessages.length > 0) { - messages['lockfile'] = lockFileMessages; - } - // Handle the top level package. const corePath = path.resolve('.', 'package.json'); const coreData: any = utils.readJSONFile(corePath); @@ -761,7 +839,8 @@ export async function ensureIntegrity(): Promise { const tsConfigDocExclude = [ 'application-extension', 'metapackage', - 'nbconvert-css' + 'nbconvert-css', + 'testing' ]; const tsConfigdocPath = path.resolve('.', 'tsconfigdoc.json'); const tsConfigdocData = utils.readJSONFile(tsConfigdocPath); @@ -797,6 +876,12 @@ export async function ensureIntegrity(): Promise { messages['top'].push('Update npm publish command in pyproject.toml'); } + // Handle the federated example application + pkgMessages = ensureFederatedExample(); + if (pkgMessages.length > 0) { + messages['@jupyterlab/example-federated-core'] = pkgMessages; + } + // Handle the JupyterLab application top package. pkgMessages = ensureJupyterlab(); if (pkgMessages.length > 0) { @@ -812,7 +897,13 @@ export async function ensureIntegrity(): Promise { ); process.exit(1); } - utils.run('jlpm install'); + try { + utils.run('jlpm install'); + } catch (error) { + // Fallback in case this script is called during editable installation + utils.run(`node jupyterlab/staging/yarn.js install`); + } + console.debug('\n\nMade integrity changes!'); console.debug('Please commit the changes by running:'); console.debug('git commit -a -m "Package integrity updates"'); diff --git a/buildutils/src/local-repository.ts b/buildutils/src/local-repository.ts index 2b89f4392053..928b88693fe6 100644 --- a/buildutils/src/local-repository.ts +++ b/buildutils/src/local-repository.ts @@ -1,6 +1,11 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +/* eslint-disable camelcase */ import * as fs from 'fs-extra'; import * as child_process from 'child_process'; -import * as crypto from 'crypto'; import * as path from 'path'; import * as os from 'os'; import * as ps from 'process'; @@ -29,7 +34,11 @@ async function startLocalRegistry(out_dir: string, port = DEFAULT_PORT) { let prev_npm = utils.run('npm config get registry', { stdio: 'pipe' }, true); let prev_yarn = ''; try { - prev_yarn = utils.run('yarn config get registry', { stdio: 'pipe' }, true); + prev_yarn = utils.run( + 'yarn config get npmRegistryServer', + { stdio: 'pipe' }, + true + ); } catch (e) { // Do nothing } @@ -131,7 +140,19 @@ packages: local_registry ]); try { - child_process.execSync(`yarn config set registry "${local_registry}"`); + child_process.execFileSync('yarn', [ + 'config', + 'set', + 'npmRegistryServer', + local_registry + ]); + child_process.execFileSync('yarn', [ + 'config', + 'set', + 'unsafeHttpWhitelist', + '--json', + '["0.0.0.0"]' + ]); } catch (e) { // yarn not available } @@ -218,45 +239,20 @@ async function stopLocalRegistry(out_dir: string) { child_process.execSync(`npm config rm registry`); } if (data.prev_yarn) { - child_process.execSync(`yarn config set registry ${data.prev_yarn}`); + child_process.execSync( + `yarn config set npmRegistryServer ${data.prev_yarn}` + ); + child_process.execSync(`yarn config unset unsafeHttpWhitelist`); } else { try { - child_process.execSync(`yarn config delete registry`); + child_process.execSync(`yarn config unset npmRegistryServer`); + child_process.execSync(`yarn config unset unsafeHttpWhitelist`); } catch (e) { // yarn not available } } } -/** - * Fix the yarn lock links in the given directory. - */ -function fixLinks(package_dir: string) { - let yarn_reg = ''; - try { - yarn_reg = utils.run('yarn config get registry', { stdio: 'pipe' }, true); - } catch (e) { - // Do nothing - } - yarn_reg = yarn_reg || 'https://registry.yarnpkg.com'; - const lock_file = path.join(package_dir, 'yarn.lock'); - console.log(`Fixing links in ${lock_file}`); - const content = fs.readFileSync(lock_file, { encoding: 'utf-8' }); - - let shasum = crypto.createHash('sha256'); - let hash = shasum.update(content); - console.log('Prior hash', hash.digest('hex')); - - const regex = /http\:\/\/0\.0\.0\.0\:\d+/g; - const new_content = content.replace(regex, yarn_reg); - - shasum = crypto.createHash('sha256'); - hash = shasum.update(new_content); - console.log('After hash', hash.digest('hex')); - - fs.writeFileSync(lock_file, new_content, 'utf8'); -} - /** * Publish the npm tar files in a given directory */ @@ -283,7 +279,7 @@ program .option('--port ', 'Port to use for the registry') .option('--path ', 'Path to use for the registry') .action(async (options: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); const out_dir = options.path || DEFAULT_OUT_DIR; await startLocalRegistry(out_dir, options.port || DEFAULT_PORT); }); @@ -292,24 +288,16 @@ program .command('stop') .option('--path ', 'Path to use for the registry') .action(async (options: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); const out_dir = options.path || DEFAULT_OUT_DIR; await stopLocalRegistry(out_dir); }); -program - .command('fix-links') - .option('--path ', 'Path to the directory with a yarn lock') - .action((options: any) => { - utils.exitOnUuncaughtException(); - fixLinks(options.path || process.cwd()); - }); - program .command('publish-dists') .option('--path ', 'Path to the directory with npm tar balls') .action((options: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); publishPackages(options.path || process.cwd()); }); diff --git a/buildutils/src/patch-release.ts b/buildutils/src/patch-release.ts old mode 100755 new mode 100644 index a4b5f73967d0..58e45b0da475 --- a/buildutils/src/patch-release.ts +++ b/buildutils/src/patch-release.ts @@ -3,7 +3,7 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -import commander from 'commander'; +import { program as commander } from 'commander'; import * as utils from './utils'; // Specify the program signature. @@ -13,7 +13,7 @@ commander .option('--all', 'Patch all JS packages instead of the changed ones') .option('--skip-commit', 'Whether to skip commit changes') .action((options: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); // Make sure we can patch release. const pyVersion = utils.getPythonVersion(); @@ -29,38 +29,25 @@ commander utils.prebump(); // Version the changed - let cmd = `lerna version patch -m \"[ci skip] New version\" --no-push`; + let cmd = `lerna version patch --no-git-tag-version --no-push`; if (options.all) { cmd += ' --force-publish=*'; } if (options.force) { cmd += ' --yes'; } - const oldVersion = utils.run( - 'git rev-parse HEAD', - { - stdio: 'pipe', - encoding: 'utf8' - }, - true - ); + + const oldVersion = utils.getJSVersion('metapackage'); utils.run(cmd); - const newVersion = utils.run( - 'git rev-parse HEAD', - { - stdio: 'pipe', - encoding: 'utf8' - }, - true - ); + const newVersion = utils.getJSVersion('metapackage'); + if (oldVersion === newVersion) { - console.debug('aborting'); // lerna didn't version anything, so we assume the user aborted throw new Error('Lerna aborted'); } // Patch the python version - utils.run('bumpversion patch'); // switches to alpha + utils.run('bumpversion patch --allow-dirty'); // switches to alpha utils.run('bumpversion release --allow-dirty'); // switches to beta utils.run('bumpversion release --allow-dirty'); // switches to rc. utils.run('bumpversion release --allow-dirty'); // switches to final. diff --git a/buildutils/src/prepare-python-release.ts b/buildutils/src/prepare-python-release.ts index 458e6071feb9..59199234971e 100644 --- a/buildutils/src/prepare-python-release.ts +++ b/buildutils/src/prepare-python-release.ts @@ -3,7 +3,7 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -import commander from 'commander'; +import { program as commander } from 'commander'; import * as crypto from 'crypto'; import * as fs from 'fs-extra'; import * as path from 'path'; @@ -13,7 +13,7 @@ import * as utils from './utils'; commander .description('Prepare the Python package for release') .action(async (options: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); const distDir = './dist'; diff --git a/buildutils/src/prepublish-check.ts b/buildutils/src/prepublish-check.ts index 8ccb6f3d945a..19d54cf08025 100644 --- a/buildutils/src/prepublish-check.ts +++ b/buildutils/src/prepublish-check.ts @@ -8,7 +8,7 @@ import * as glob from 'glob'; import * as path from 'path'; import * as utils from './utils'; -utils.exitOnUuncaughtException(); +utils.exitOnUncaughtException(); utils.run('npm run build:packages'); diff --git a/buildutils/src/prompt.d.ts b/buildutils/src/prompt.d.ts deleted file mode 100644 index 388a2d99394f..000000000000 --- a/buildutils/src/prompt.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Type definitions for sort-package-json v1.7.1 -// https://github.com/keithamus/sort-package-json -// Definitions by: Steven Silvester - -declare module 'prompt' { - export function start(): void; - - export function get( - items: string[], - callback: (err: Error, result: any) => void - ): void; -} diff --git a/buildutils/src/publish.ts b/buildutils/src/publish.ts index 3237841b18ff..18dbbde66e02 100644 --- a/buildutils/src/publish.ts +++ b/buildutils/src/publish.ts @@ -3,7 +3,7 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -import commander from 'commander'; +import { program as commander } from 'commander'; import * as path from 'path'; import * as os from 'os'; import { handlePackage } from './update-dist-tag'; @@ -30,7 +30,7 @@ commander .option('--yes', 'Publish without confirmation') .option('--dry-run', 'Do not actually push any assets') .action(async (options: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); // No-op if we're in release helper dry run if (process.env.RH_DRY_RUN === 'true') { diff --git a/buildutils/src/read-package-json.d.ts b/buildutils/src/read-package-json.d.ts deleted file mode 100644 index 6f8d125fc92b..000000000000 --- a/buildutils/src/read-package-json.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Type definitions for sort-package-json v1.7.1 -// https://github.com/keithamus/sort-package-json -// Definitions by: Steven Silvester - -declare module 'sort-package-json' { - function sort(value: any): any; - export = sort; -} diff --git a/buildutils/src/remove-package.ts b/buildutils/src/remove-package.ts old mode 100755 new mode 100644 diff --git a/buildutils/src/update-core-mode.ts b/buildutils/src/update-core-mode.ts index aeb5a4ac8101..615443f73327 100644 --- a/buildutils/src/update-core-mode.ts +++ b/buildutils/src/update-core-mode.ts @@ -6,6 +6,7 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import * as utils from './utils'; +import { upgradeLock } from './update-staging-lock'; // Run integrity to update the dev_mode package.json utils.run('jlpm integrity'); @@ -22,7 +23,7 @@ data['jupyterlab']['linkedPackages'] = {}; const staging = './jupyterlab/staging'; // Ensure a clean staging directory. -const keep = ['yarn.js', '.yarnrc']; +const keep = ['yarn.js', '.yarnrc.yml']; fs.readdirSync(staging).forEach(name => { if (keep.indexOf(name) === -1) { fs.removeSync(path.join(staging, name)); @@ -62,13 +63,14 @@ fs.copySync( path.join('.', 'yarn.lock'), path.join('.', 'jupyterlab', 'staging', 'yarn.lock') ); -utils.run('jlpm', { cwd: staging }); -try { - utils.run('jlpm yarn-deduplicate -s fewer --fail', { cwd: staging }); -} catch { - // re-run install if we deduped packages! - utils.run('jlpm', { cwd: staging }); -} +process.env.YARN_UNSAFE_HTTP_WHITELIST = '0.0.0.0'; +upgradeLock('@jupyterlab/*', { + lock: path.join(staging, 'yarn.lock'), + cwd: staging +}); +utils.run('jlpm dlx yarn-berry-deduplicate --strategy fewerHighest', { + cwd: staging +}); // Build the core assets. utils.run('jlpm run build:prod:release', { cwd: staging }); diff --git a/buildutils/src/update-dependency.ts b/buildutils/src/update-dependency.ts index 721dcf74b64f..945fe1f03e0f 100755 --- a/buildutils/src/update-dependency.ts +++ b/buildutils/src/update-dependency.ts @@ -8,7 +8,7 @@ import * as path from 'path'; import * as utils from './utils'; import packageJson from 'package-json'; -import commander from 'commander'; +import { program as commander } from 'commander'; import semver from 'semver'; const versionCache = new Map(); diff --git a/buildutils/src/update-dist-tag.ts b/buildutils/src/update-dist-tag.ts old mode 100755 new mode 100644 index 719daff97802..85e7ca6184d5 --- a/buildutils/src/update-dist-tag.ts +++ b/buildutils/src/update-dist-tag.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import * as utils from './utils'; import packageJson from 'package-json'; -import commander from 'commander'; +import { program as commander } from 'commander'; import semver from 'semver'; /** diff --git a/buildutils/src/update-staging-lock.ts b/buildutils/src/update-staging-lock.ts new file mode 100644 index 000000000000..7a227175b105 --- /dev/null +++ b/buildutils/src/update-staging-lock.ts @@ -0,0 +1,161 @@ +#!/usr/bin/env node +/* ----------------------------------------------------------------------------- +| Copyright (c) Jupyter Development Team. +| Distributed under the terms of the Modified BSD License. +|----------------------------------------------------------------------------*/ + +import { structUtils } from '@yarnpkg/core'; +import { parseSyml, stringifySyml } from '@yarnpkg/parsers'; +import { program } from 'commander'; +import fs from 'fs'; +import micromatch from 'micromatch'; +import semver from 'semver'; +import { exitOnUncaughtException, run } from './utils'; + +/** + * Yarn lock entry + * + * Copied from https://github.com/christophehurpeau/yarn-deduplicate/blob/yarn-berry/src/yarnlock.ts + */ +type YarnEntry = { + version: string; + resolution: string; + dependencies?: Record; + checksum?: string; + languageName?: 'node'; + linkType?: 'hard' | 'soft'; +}; + +// Copied from https://github.com/yarnpkg/berry/blob/d85702c61e3b19715c728fa9d2ecec68dcbf39b2/packages/yarnpkg-core/sources/Project.ts#L1988 +const yarnLockHeader = `${[ + `# This file is generated by running "yarn install" inside your project.\n`, + `# Manual changes might be lost - proceed with caution!\n` +].join(``)}\n`; + +export function upgradeLock( + packages: string, + options: { lock: string; cwd?: string } +): void { + exitOnUncaughtException(); + + const lockFile = options.lock ?? 'yarn.lock'; + + // Load current yarn.lock + const pkgs = loadPackages(lockFile); + const pkgToDescriptor = new Map(); + for (const pkg in pkgs) { + if (pkg.startsWith('__')) { + continue; + } + const name = extractNameFromDescriptor(pkgs[pkg].resolution); + + if (pkgToDescriptor.has(name)) { + pkgToDescriptor.get(name)!.push(pkg); + } else { + pkgToDescriptor.set(name, [pkg]); + } + } + + // Update the yarn.lock file recursevily at most 5 times (normally twice is enough) + let counter = 5; + do { + run('jlpm install', { cwd: options.cwd }); + } while ( + upgradeSelectedPackages(lockFile, pkgToDescriptor, packages, pkgs) && + counter-- > 0 + ); + + // Check that the yarn.lock is immutable + run('jlpm install --immutable', { cwd: options.cwd }); +} + +/** + * Downgrade package versions to match old locked version expect + * for the package matching the provided pattern. + * + * @param lockFile yarn.lock file + * @param pkgToDescriptor Package name to yarn descriptors + * @param packages Package pattern to update + * @param pkgs Original package versions + * @returns Whether some versions have been downgraded or not + */ +function upgradeSelectedPackages( + lockFile: string, + pkgToDescriptor: Map, + packages: string, + pkgs: Record +): boolean { + let hasChange = false; + const newPkgs = loadPackages(lockFile); + for (const pkg in newPkgs) { + if (pkg.startsWith('__')) { + continue; + } + const name = extractNameFromDescriptor(newPkgs[pkg].resolution); + if (pkgToDescriptor.has(name)) { + if (!micromatch.isMatch(name, packages)) { + let noMatch = true; + for (const origDescriptor of pkgToDescriptor.get(name)!) { + const origPkg = pkgs[origDescriptor]; + if ( + pkg.split(',').every(desc => { + const parsedDesc = structUtils.parseDescriptor(desc.trim()); + const range = structUtils.parseRange(parsedDesc.range); + return ( + !semver.validRange(range.selector) || + semver.satisfies(origPkg.version, range.selector) + ); + }) + ) { + noMatch = false; + if (origPkg.version !== newPkgs[pkg].version) { + hasChange = true; + console.log( + `Downgrade '${name}' from ${newPkgs[pkg].version} to ${origPkg.version}` + ); + newPkgs[pkg] = origPkg; + } + break; + } + } + if (noMatch) { + console.warn(`No package found for '${pkg}'.`); + } + } else { + console.log(`Ignoring package '${pkg}'.`); + } + } else { + console.warn(`New package '${pkg}' added.`); + } + } + + if (hasChange) { + const newLock = yarnLockHeader + stringifySyml(newPkgs); + + fs.writeFileSync(lockFile, newLock, { encoding: 'utf-8' }); + } + return hasChange; +} + +function extractNameFromDescriptor(name: string): string { + const descriptor = structUtils.parseDescriptor(name.split(',')[0].trim()); + return descriptor.scope + ? `@${descriptor.scope}/${descriptor.name}` + : descriptor.name; +} + +function loadPackages(lockFile: string): Record { + const yarnLock = fs.readFileSync(lockFile, { encoding: 'utf-8' }); + return parseSyml(yarnLock); +} + +if (require.main === module) { + program + .description( + 'Update yarn.lock at minima; aka only packages matching the provided pattern (support fnmatch syntax) are updated.' + ) + .option('--lock', 'yarn.lock file name', 'yarn.lock') + .arguments('packages') + .action(upgradeLock); + program.parse(process.argv); +} diff --git a/buildutils/src/utils.ts b/buildutils/src/utils.ts index 96d8b33f6c23..10db465efe98 100644 --- a/buildutils/src/utils.ts +++ b/buildutils/src/utils.ts @@ -1,10 +1,17 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +/* global NodeRequire */ import path from 'path'; import glob from 'glob'; import fs from 'fs-extra'; import childProcess from 'child_process'; import { DepGraph } from 'dependency-graph'; import sortPackageJson from 'sort-package-json'; -import { JSONExt, JSONObject } from '@lumino/coreutils'; + +import assert from 'assert'; type Dict = { [key: string]: T }; @@ -13,7 +20,7 @@ const backSlash = /\\/g; /** * Exit with an error code on uncaught error. */ -export function exitOnUuncaughtException(): void { +export function exitOnUncaughtException(): void { process.on('uncaughtException', function (err: any) { if (err.status || err.stdout || err.stderr) { console.error(`Status: ${err.status}`); @@ -78,13 +85,13 @@ export function getCorePaths(): string[] { * * @param data - The package data. * - * @oaram pkgJsonPath - The path to the package.json file. + * @param pkgJsonPath - The path to the package.json file. * * @returns Whether the file has changed. */ export function writePackageData( pkgJsonPath: string, - data: JSONObject + data: Record ): boolean { const text = JSON.stringify(sortPackageJson(data), null, 2) + '\n'; const orig = fs.readFileSync(pkgJsonPath, 'utf8').split('\r\n').join('\n'); @@ -109,7 +116,10 @@ export function readJSONFile(filePath: string): any { /** * Write a json file. */ -export function writeJSONFile(filePath: string, data: JSONObject): boolean { +export function writeJSONFile( + filePath: string, + data: Record +): boolean { function sortObjByKey(value: any): any { // https://stackoverflow.com/a/35810961 return typeof value === 'object' @@ -131,11 +141,15 @@ export function writeJSONFile(filePath: string, data: JSONObject): boolean { } catch (e) { // no-op } - if (!JSONExt.deepEqual(data, orig)) { + + // If values do not match, overwrite file. + try { + assert.deepStrictEqual(data, orig); + return false; + } catch (error) { fs.writeFileSync(filePath, text, 'utf8'); return true; } - return false; } /** @@ -199,7 +213,7 @@ export function checkStatus(cmd: string): number | null { * Get the current version of JupyterLab */ export function getPythonVersion(): string { - const cmd = 'python setup.py --version'; + const cmd = 'hatchling version'; const lines = run(cmd, { stdio: 'pipe' }, true).split('\n'); return lines[lines.length - 1]; } @@ -228,11 +242,17 @@ export function prebump(): void { encoding: 'utf8' }); if (status.length > 0) { + const diff = run('git diff', { + stdio: 'pipe', + encoding: 'utf8' + }); throw new Error( `Must be in a clean git state with no untracked files. Run "git status" to see the issues. -${status}` +${status} + +${diff}` ); } } @@ -241,14 +261,7 @@ ${status}` * Post-bump. */ export function postbump(commit = true): void { - // Get the current version. - const curr = getPythonVersion(); - - // Update the dev mode version. - const filePath = path.resolve(path.join('.', 'dev_mode', 'package.json')); - const data = readJSONFile(filePath); - data.jupyterlab.version = curr; - writeJSONFile(filePath, data); + run('jlpm run integrity'); // Commit changes. if (commit) { @@ -334,6 +347,25 @@ export function getPackageGraph(): DepGraph> { return graph; } +function isModuleDir(current: string, moduleDirs: string[]): boolean { + return moduleDirs.some(dir => current.endsWith(dir)); +} + +function findPackageJson(base: string, moduleDirs: string[]): NodeRequire { + const { root } = path.parse(base); + let current = base; + + while (current !== root && !isModuleDir(current, moduleDirs)) { + const pkgJsonPath = path.join(current, 'package.json'); + if (fs.existsSync(pkgJsonPath)) { + return require(pkgJsonPath); + } + current = path.resolve(current, '..'); + } + throw new Error( + `Unable to find package.json for '${base}', moduleDirs = '${moduleDirs[0]}'` + ); +} /** * Resolve a `package.json` in the `module` starting at resolution from the `parentModule`. * @@ -347,12 +379,30 @@ function requirePackage(parentModule: string, module: string): NodeRequire { try { parentModulePath = require.resolve(parentModule); } catch { - return require(packagePath); + try { + return require(packagePath); + } catch { + return findPackageJson(module, [path.resolve(packagePath, '..')]); + } } - const requirePath = require.resolve(packagePath, { - paths: [parentModulePath] - }); - return require(requirePath); + + try { + // This may fail for package not exporting `package.json` in their exports map + // https://github.com/nodejs/node/issues/33460 + const requirePath = require.resolve(packagePath, { + paths: [parentModulePath] + }); + return require(requirePath); + } catch { + // If it fails, try to find the package.json by going parent to parent + // Inspired by https://github.com/rollup/plugins/blob/540767b947cfad0dd06a278b977b8ce05da9593c/packages/node-resolve/src/package/utils.js#L11 + const base = require.resolve(module, { + paths: [parentModulePath] + }); + return findPackageJson(base, [parentModulePath]); + } + + throw new Error(`Unable to find package.json for '${module}'.`); } /** diff --git a/buildutils/src/yarnlock.d.ts b/buildutils/src/yarnlock.d.ts deleted file mode 100644 index 82a1db6e65f2..000000000000 --- a/buildutils/src/yarnlock.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@yarnpkg/lockfile'; diff --git a/buildutils/template/babel.config.js b/buildutils/template/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/buildutils/template/babel.config.js +++ b/buildutils/template/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/buildutils/template/jest.config.js b/buildutils/template/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/buildutils/template/jest.config.js +++ b/buildutils/template/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/buildutils/template/package.json b/buildutils/template/package.json index 62c247207bff..a7627faf296f 100644 --- a/buildutils/template/package.json +++ b/buildutils/template/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/template", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Package Template", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -23,26 +23,24 @@ "files": [ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "schema/*.json", - "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}" + "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", - "build:all": "npm run build", "build:test": "tsc --build tsconfig.test.json", "clean": "rimraf lib tsconfig.tsbuildinfo", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", "rimraf": "~3.0.0", - "ts-jest": "^26.3.0", - "typescript": "~4.1.3" + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/buildutils/template/tsconfig.test.json b/buildutils/template/tsconfig.test.json index 717c38a1f87b..206275947f45 100644 --- a/buildutils/template/tsconfig.test.json +++ b/buildutils/template/tsconfig.test.json @@ -6,7 +6,7 @@ "path": "." }, { - "path": "../../testutils" + "path": "../../packages/testing" } ] } diff --git a/buildutils/tsconfig.json b/buildutils/tsconfig.json index 945e3ce9d755..7095bede4bd5 100644 --- a/buildutils/tsconfig.json +++ b/buildutils/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "outDir": "lib", "rootDir": "src", - "module": "commonjs" + "module": "commonjs", + "moduleResolution": "node16" }, "include": ["src/*"], "references": [] diff --git a/clean.py b/clean.py index 7f310cfadd76..2672d280bf3e 100644 --- a/clean.py +++ b/clean.py @@ -1,3 +1,6 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + import os import subprocess @@ -6,16 +9,18 @@ # Workaround for https://github.com/git-for-windows/git/issues/607 if os.name == "nt": - for (root, dnames, files) in os.walk(here): + for root, dnames, _ in os.walk(here): if "node_modules" in dnames: - subprocess.check_call(["rmdir", "/s", "/q", "node_modules"], cwd=root, shell=True) + subprocess.check_call( + ["rmdir", "/s", "/q", "node_modules"], cwd=root, shell=True # noqa S602 S607 + ) dnames.remove("node_modules") -subprocess.check_call("python -m pip uninstall -y jupyterlab".split(), cwd=here) +subprocess.check_call("python -m pip uninstall -y jupyterlab".split(), cwd=here) # noqa S603 -def resolvePattern(pat): +def resolve_pattern(pat): """handle a leading `#` or `@` in a pattern""" pat = pat.strip() @@ -30,7 +35,7 @@ def resolvePattern(pat): # get the exclude patterns listed in .cleanignore with open(os.path.join(here, ".cleanignore")) as f: - git_clean_exclude = [f"--exclude={pat}" for line in f for pat in resolvePattern(line)] + git_clean_exclude = [f"--exclude={pat}" for line in f for pat in resolve_pattern(line)] -git_clean_command = ["git", "clean", "-dfx"] + git_clean_exclude -subprocess.check_call(git_clean_command, cwd=here) +git_clean_command = ["git", "clean", "-dfx", *git_clean_exclude] +subprocess.check_call(git_clean_command, cwd=here) # noqa S603 diff --git a/conftest.py b/conftest.py index 468480a387e3..70007f557e7b 100644 --- a/conftest.py +++ b/conftest.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. diff --git a/design/notebook.md b/design/notebook.md index 6c6edcbafe68..c51850409861 100644 --- a/design/notebook.md +++ b/design/notebook.md @@ -50,9 +50,9 @@ Users should be able to: - Select multiple cells at once (mouse, shortcut) - Move cell(s) up and down (mouse) - Use notebook operations - - Clear All Outputs (command palette) + - Clear Outputs of All Cells (command palette) - Interrupt Kernel (command palette, shortcut, toolbar) - - Restart Kernel & Clear Outputs (command palette) + - Restart Kernel & Clear Outputs of All Cells (command palette) - Restart Kernel & Run All (command palette) - Run All Cells (command palette) - Switch Kernel (command palette, toolbar) diff --git a/dev_mode/bootstrap.js b/dev_mode/bootstrap.js index 1b6fc698b24f..5a44157bd40e 100644 --- a/dev_mode/bootstrap.js +++ b/dev_mode/bootstrap.js @@ -1,7 +1,7 @@ -/*----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ // We copy some of the pageconfig parsing logic in @jupyterlab/coreutils // below, since this must run before any other files are loaded (including @@ -40,26 +40,6 @@ function getOption(name) { // eslint-disable-next-line no-undef __webpack_public_path__ = getOption('fullStaticUrl') + '/'; -// Promise.allSettled polyfill, until our supported browsers implement it -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled -if (Promise.allSettled === undefined) { - Promise.allSettled = promises => - Promise.all( - promises.map(promise => - promise.then( - value => ({ - status: 'fulfilled', - value - }), - reason => ({ - status: 'rejected', - reason - }) - ) - ) - ); -} - function loadScript(url) { return new Promise((resolve, reject) => { const newScript = document.createElement('script'); diff --git a/dev_mode/index.js b/dev_mode/index.js index b5e694957cd7..bc177ee113bc 100644 --- a/dev_mode/index.js +++ b/dev_mode/index.js @@ -1,28 +1,10 @@ -/*----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ import { PageConfig } from '@jupyterlab/coreutils'; -// Promise.allSettled polyfill, until our supported browsers implement it -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled -if (Promise.allSettled === undefined) { - Promise.allSettled = promises => - Promise.all( - promises.map(promise => - promise - .then(value => ({ - status: "fulfilled", - value, - }), reason => ({ - status: "rejected", - reason, - })) - ) - ); -} - import './style.js'; async function createModule(scope, module) { @@ -87,8 +69,6 @@ export async function main() { PageConfig.getOption('federated_extensions') ); - var futureSkipStylesForDisabled = (PageConfig.getOption('futureSkipStylesForDisabled') || '').toLowerCase() === 'true'; - const queuedFederated = []; extensions.forEach(data => { @@ -101,7 +81,7 @@ export async function main() { federatedMimeExtensionPromises.push(createModule(data.name, data.mimeExtension)); } - if (data.style && (!futureSkipStylesForDisabled || !PageConfig.Extension.isDisabled(data.name))) { + if (data.style && !PageConfig.Extension.isDisabled(data.name)) { federatedStylePromises.push(createModule(data.name, data.style)); } }); @@ -215,7 +195,6 @@ export async function main() { var devMode = (PageConfig.getOption('devMode') || '').toLowerCase() === 'true'; if (exposeAppInBrowser || devMode) { - window.jupyterlab = lab; window.jupyterapp = lab; } diff --git a/dev_mode/package.json b/dev_mode/package.json index 18a6f6a5550d..6c7214766734 100644 --- a/dev_mode/package.json +++ b/dev_mode/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/application-top", - "version": "3.6.6", + "version": "4.0.8", "private": true, "license": "BSD-3-Clause", "scripts": { @@ -8,223 +8,222 @@ "build:dev": "npm run build", "build:prod": "webpack --config webpack.prod.config.js", "build:prod:minimize": "webpack --config webpack.prod.minimize.config.js", + "build:prod:minimize:report": "npm run build:prod:minimize:stats && webpack-bundle-analyzer --no-open --mode static --report static/webpack-bundle-analyzer.html stats.json static", + "build:prod:minimize:stats": "webpack --profile --config webpack.prod.minimize.config.js --json > stats.json", "build:prod:release": "webpack --config webpack.prod.release.config.js", - "build:prod:stats": "webpack --profile --config webpack.prod.minimize.config.js --json > stats.json", "build:stats": "webpack --profile --json > stats.json", "clean": "rimraf build", "prepublishOnly": "npm run build", "watch": "webpack --watch" }, "resolutions": { - "@jupyter/ydoc": "~0.2.4", - "@jupyterlab/application": "~3.6.6", - "@jupyterlab/application-extension": "~3.6.6", - "@jupyterlab/apputils": "~3.6.6", - "@jupyterlab/apputils-extension": "~3.6.6", - "@jupyterlab/attachments": "~3.6.6", - "@jupyterlab/cell-toolbar": "~3.6.6", - "@jupyterlab/cell-toolbar-extension": "~3.6.6", - "@jupyterlab/cells": "~3.6.6", - "@jupyterlab/celltags": "~3.6.6", - "@jupyterlab/celltags-extension": "~3.6.6", - "@jupyterlab/codeeditor": "~3.6.6", - "@jupyterlab/codemirror": "~3.6.6", - "@jupyterlab/codemirror-extension": "~3.6.6", - "@jupyterlab/collaboration": "~3.6.6", - "@jupyterlab/collaboration-extension": "~3.6.6", - "@jupyterlab/completer": "~3.6.6", - "@jupyterlab/completer-extension": "~3.6.6", - "@jupyterlab/console": "~3.6.6", - "@jupyterlab/console-extension": "~3.6.6", - "@jupyterlab/coreutils": "~5.6.6", - "@jupyterlab/csvviewer": "~3.6.6", - "@jupyterlab/csvviewer-extension": "~3.6.6", - "@jupyterlab/debugger": "~3.6.6", - "@jupyterlab/debugger-extension": "~3.6.6", - "@jupyterlab/docmanager": "~3.6.6", - "@jupyterlab/docmanager-extension": "~3.6.6", - "@jupyterlab/docprovider": "~3.6.6", - "@jupyterlab/docprovider-extension": "~3.6.6", - "@jupyterlab/docregistry": "~3.6.6", - "@jupyterlab/documentsearch": "~3.6.6", - "@jupyterlab/documentsearch-extension": "~3.6.6", - "@jupyterlab/extensionmanager": "~3.6.6", - "@jupyterlab/extensionmanager-extension": "~3.6.6", - "@jupyterlab/filebrowser": "~3.6.6", - "@jupyterlab/filebrowser-extension": "~3.6.6", - "@jupyterlab/fileeditor": "~3.6.6", - "@jupyterlab/fileeditor-extension": "~3.6.6", - "@jupyterlab/help-extension": "~3.6.6", - "@jupyterlab/htmlviewer": "~3.6.6", - "@jupyterlab/htmlviewer-extension": "~3.6.6", - "@jupyterlab/hub-extension": "~3.6.6", - "@jupyterlab/imageviewer": "~3.6.6", - "@jupyterlab/imageviewer-extension": "~3.6.6", - "@jupyterlab/inspector": "~3.6.6", - "@jupyterlab/inspector-extension": "~3.6.6", - "@jupyterlab/javascript-extension": "~3.6.6", - "@jupyterlab/json-extension": "~3.6.6", - "@jupyterlab/launcher": "~3.6.6", - "@jupyterlab/launcher-extension": "~3.6.6", - "@jupyterlab/logconsole": "~3.6.6", - "@jupyterlab/logconsole-extension": "~3.6.6", - "@jupyterlab/mainmenu": "~3.6.6", - "@jupyterlab/mainmenu-extension": "~3.6.6", - "@jupyterlab/markdownviewer": "~3.6.6", - "@jupyterlab/markdownviewer-extension": "~3.6.6", - "@jupyterlab/mathjax2": "~3.6.6", - "@jupyterlab/mathjax2-extension": "~3.6.6", - "@jupyterlab/metapackage": "~3.6.6", - "@jupyterlab/nbconvert-css": "~3.6.6", - "@jupyterlab/nbformat": "~3.6.6", - "@jupyterlab/notebook": "~3.6.6", - "@jupyterlab/notebook-extension": "~3.6.6", - "@jupyterlab/observables": "~4.6.6", - "@jupyterlab/outputarea": "~3.6.6", - "@jupyterlab/pdf-extension": "~3.6.6", - "@jupyterlab/property-inspector": "~3.6.6", - "@jupyterlab/rendermime": "~3.6.6", - "@jupyterlab/rendermime-extension": "~3.6.6", - "@jupyterlab/rendermime-interfaces": "~3.6.6", - "@jupyterlab/running": "~3.6.6", - "@jupyterlab/running-extension": "~3.6.6", - "@jupyterlab/services": "../packages/services", - "@jupyterlab/settingeditor": "~3.6.6", - "@jupyterlab/settingeditor-extension": "~3.6.6", - "@jupyterlab/settingregistry": "~3.6.6", - "@jupyterlab/shared-models": "~3.6.6", - "@jupyterlab/shortcuts-extension": "~3.6.6", - "@jupyterlab/statedb": "~3.6.6", - "@jupyterlab/statusbar": "~3.6.6", - "@jupyterlab/statusbar-extension": "~3.6.6", - "@jupyterlab/terminal": "~3.6.6", - "@jupyterlab/terminal-extension": "~3.6.6", - "@jupyterlab/theme-dark-extension": "~3.6.6", - "@jupyterlab/theme-light-extension": "~3.6.6", - "@jupyterlab/toc": "~5.6.6", - "@jupyterlab/toc-extension": "~5.6.6", - "@jupyterlab/tooltip": "~3.6.6", - "@jupyterlab/tooltip-extension": "~3.6.6", - "@jupyterlab/translation": "~3.6.6", - "@jupyterlab/translation-extension": "~3.6.6", - "@jupyterlab/ui-components": "~3.6.6", - "@jupyterlab/ui-components-extension": "~3.6.6", - "@jupyterlab/vdom": "~3.6.6", - "@jupyterlab/vdom-extension": "~3.6.6", - "@jupyterlab/vega5-extension": "~3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/application": "^1.31.4", - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/domutils": "^1.8.0", - "@lumino/dragdrop": "^1.13.0", - "@lumino/messaging": "^1.10.0", - "@lumino/properties": "^1.8.0", - "@lumino/signaling": "^1.10.0", - "@lumino/virtualdom": "^1.14.0", - "@lumino/widgets": "^1.37.2", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "yjs": "^13.5.17" + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.2.0", + "@codemirror/view": "^6.9.6", + "@jupyter/ydoc": "~1.0.2", + "@jupyterlab/application": "~4.0.8", + "@jupyterlab/application-extension": "~4.0.8", + "@jupyterlab/apputils": "~4.1.8", + "@jupyterlab/apputils-extension": "~4.0.8", + "@jupyterlab/attachments": "~4.0.8", + "@jupyterlab/cell-toolbar": "~4.0.8", + "@jupyterlab/cell-toolbar-extension": "~4.0.8", + "@jupyterlab/cells": "~4.0.8", + "@jupyterlab/celltags-extension": "~4.0.8", + "@jupyterlab/codeeditor": "~4.0.8", + "@jupyterlab/codemirror": "~4.0.8", + "@jupyterlab/codemirror-extension": "~4.0.8", + "@jupyterlab/completer": "~4.0.8", + "@jupyterlab/completer-extension": "~4.0.8", + "@jupyterlab/console": "~4.0.8", + "@jupyterlab/console-extension": "~4.0.8", + "@jupyterlab/coreutils": "~6.0.8", + "@jupyterlab/csvviewer": "~4.0.8", + "@jupyterlab/csvviewer-extension": "~4.0.8", + "@jupyterlab/debugger": "~4.0.8", + "@jupyterlab/debugger-extension": "~4.0.8", + "@jupyterlab/docmanager": "~4.0.8", + "@jupyterlab/docmanager-extension": "~4.0.8", + "@jupyterlab/docregistry": "~4.0.8", + "@jupyterlab/documentsearch": "~4.0.8", + "@jupyterlab/documentsearch-extension": "~4.0.8", + "@jupyterlab/extensionmanager": "~4.0.8", + "@jupyterlab/extensionmanager-extension": "~4.0.8", + "@jupyterlab/filebrowser": "~4.0.8", + "@jupyterlab/filebrowser-extension": "~4.0.8", + "@jupyterlab/fileeditor": "~4.0.8", + "@jupyterlab/fileeditor-extension": "~4.0.8", + "@jupyterlab/help-extension": "~4.0.8", + "@jupyterlab/htmlviewer": "~4.0.8", + "@jupyterlab/htmlviewer-extension": "~4.0.8", + "@jupyterlab/hub-extension": "~4.0.8", + "@jupyterlab/imageviewer": "~4.0.8", + "@jupyterlab/imageviewer-extension": "~4.0.8", + "@jupyterlab/inspector": "~4.0.8", + "@jupyterlab/inspector-extension": "~4.0.8", + "@jupyterlab/javascript-extension": "~4.0.8", + "@jupyterlab/json-extension": "~4.0.8", + "@jupyterlab/launcher": "~4.0.8", + "@jupyterlab/launcher-extension": "~4.0.8", + "@jupyterlab/logconsole": "~4.0.8", + "@jupyterlab/logconsole-extension": "~4.0.8", + "@jupyterlab/lsp": "~4.0.8", + "@jupyterlab/lsp-extension": "~4.0.8", + "@jupyterlab/mainmenu": "~4.0.8", + "@jupyterlab/mainmenu-extension": "~4.0.8", + "@jupyterlab/markdownviewer": "~4.0.8", + "@jupyterlab/markdownviewer-extension": "~4.0.8", + "@jupyterlab/markedparser-extension": "~4.0.8", + "@jupyterlab/mathjax-extension": "~4.0.8", + "@jupyterlab/metadataform": "~4.0.8", + "@jupyterlab/metadataform-extension": "~4.0.8", + "@jupyterlab/metapackage": "~4.0.8", + "@jupyterlab/nbconvert-css": "~4.0.8", + "@jupyterlab/nbformat": "~4.0.8", + "@jupyterlab/notebook": "~4.0.8", + "@jupyterlab/notebook-extension": "~4.0.8", + "@jupyterlab/observables": "~5.0.8", + "@jupyterlab/outputarea": "~4.0.8", + "@jupyterlab/pdf-extension": "~4.0.8", + "@jupyterlab/property-inspector": "~4.0.8", + "@jupyterlab/rendermime": "~4.0.8", + "@jupyterlab/rendermime-extension": "~4.0.8", + "@jupyterlab/rendermime-interfaces": "~3.8.8", + "@jupyterlab/running": "~4.0.8", + "@jupyterlab/running-extension": "~4.0.8", + "@jupyterlab/services": "~7.0.8", + "@jupyterlab/settingeditor": "~4.0.8", + "@jupyterlab/settingeditor-extension": "~4.0.8", + "@jupyterlab/settingregistry": "~4.0.8", + "@jupyterlab/shortcuts-extension": "~4.0.8", + "@jupyterlab/statedb": "~4.0.8", + "@jupyterlab/statusbar": "~4.0.8", + "@jupyterlab/statusbar-extension": "~4.0.8", + "@jupyterlab/terminal": "~4.0.8", + "@jupyterlab/terminal-extension": "~4.0.8", + "@jupyterlab/theme-dark-extension": "~4.0.8", + "@jupyterlab/theme-light-extension": "~4.0.8", + "@jupyterlab/toc": "~6.0.8", + "@jupyterlab/toc-extension": "~6.0.8", + "@jupyterlab/tooltip": "~4.0.8", + "@jupyterlab/tooltip-extension": "~4.0.8", + "@jupyterlab/translation": "~4.0.8", + "@jupyterlab/translation-extension": "~4.0.8", + "@jupyterlab/ui-components": "~4.0.8", + "@jupyterlab/ui-components-extension": "~4.0.8", + "@jupyterlab/vega5-extension": "~4.0.8", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lumino/algorithm": "^2.0.0", + "@lumino/application": "^2.0.1", + "@lumino/commands": "^2.0.1", + "@lumino/coreutils": "^2.0.0", + "@lumino/datagrid": "^2.0.1", + "@lumino/disposable": "^2.0.0", + "@lumino/domutils": "^2.0.0", + "@lumino/dragdrop": "^2.0.0", + "@lumino/keyboard": "^2.0.0", + "@lumino/messaging": "^2.0.0", + "@lumino/polling": "^2.0.0", + "@lumino/properties": "^2.0.0", + "@lumino/signaling": "^2.0.0", + "@lumino/virtualdom": "^2.0.0", + "@lumino/widgets": "^2.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "yjs": "^13.5.40" }, "dependencies": { - "@jupyterlab/application": "~3.6.6", - "@jupyterlab/application-extension": "~3.6.6", - "@jupyterlab/apputils-extension": "~3.6.6", - "@jupyterlab/cell-toolbar-extension": "~3.6.6", - "@jupyterlab/celltags-extension": "~3.6.6", - "@jupyterlab/codemirror-extension": "~3.6.6", - "@jupyterlab/collaboration-extension": "~3.6.6", - "@jupyterlab/completer-extension": "~3.6.6", - "@jupyterlab/console-extension": "~3.6.6", - "@jupyterlab/coreutils": "~5.6.6", - "@jupyterlab/csvviewer-extension": "~3.6.6", - "@jupyterlab/debugger-extension": "~3.6.6", - "@jupyterlab/docmanager-extension": "~3.6.6", - "@jupyterlab/docprovider-extension": "~3.6.6", - "@jupyterlab/documentsearch-extension": "~3.6.6", - "@jupyterlab/extensionmanager-extension": "~3.6.6", - "@jupyterlab/filebrowser-extension": "~3.6.6", - "@jupyterlab/fileeditor-extension": "~3.6.6", - "@jupyterlab/help-extension": "~3.6.6", - "@jupyterlab/htmlviewer-extension": "~3.6.6", - "@jupyterlab/hub-extension": "~3.6.6", - "@jupyterlab/imageviewer-extension": "~3.6.6", - "@jupyterlab/inspector-extension": "~3.6.6", - "@jupyterlab/javascript-extension": "~3.6.6", - "@jupyterlab/json-extension": "~3.6.6", - "@jupyterlab/launcher-extension": "~3.6.6", - "@jupyterlab/logconsole-extension": "~3.6.6", - "@jupyterlab/mainmenu-extension": "~3.6.6", - "@jupyterlab/markdownviewer-extension": "~3.6.6", - "@jupyterlab/mathjax2-extension": "~3.6.6", - "@jupyterlab/notebook-extension": "~3.6.6", - "@jupyterlab/pdf-extension": "~3.6.6", - "@jupyterlab/rendermime-extension": "~3.6.6", - "@jupyterlab/running-extension": "~3.6.6", - "@jupyterlab/settingeditor-extension": "~3.6.6", - "@jupyterlab/shortcuts-extension": "~3.6.6", - "@jupyterlab/statusbar-extension": "~3.6.6", - "@jupyterlab/terminal-extension": "~3.6.6", - "@jupyterlab/theme-dark-extension": "~3.6.6", - "@jupyterlab/theme-light-extension": "~3.6.6", - "@jupyterlab/toc-extension": "~5.6.6", - "@jupyterlab/tooltip-extension": "~3.6.6", - "@jupyterlab/translation-extension": "~3.6.6", - "@jupyterlab/ui-components-extension": "~3.6.6", - "@jupyterlab/vdom-extension": "~3.6.6", - "@jupyterlab/vega5-extension": "~3.6.6" + "@jupyterlab/application": "~4.0.8", + "@jupyterlab/application-extension": "~4.0.8", + "@jupyterlab/apputils-extension": "~4.0.8", + "@jupyterlab/cell-toolbar-extension": "~4.0.8", + "@jupyterlab/celltags-extension": "~4.0.8", + "@jupyterlab/codemirror-extension": "~4.0.8", + "@jupyterlab/completer-extension": "~4.0.8", + "@jupyterlab/console-extension": "~4.0.8", + "@jupyterlab/coreutils": "~6.0.8", + "@jupyterlab/csvviewer-extension": "~4.0.8", + "@jupyterlab/debugger-extension": "~4.0.8", + "@jupyterlab/docmanager-extension": "~4.0.8", + "@jupyterlab/documentsearch-extension": "~4.0.8", + "@jupyterlab/extensionmanager-extension": "~4.0.8", + "@jupyterlab/filebrowser-extension": "~4.0.8", + "@jupyterlab/fileeditor-extension": "~4.0.8", + "@jupyterlab/help-extension": "~4.0.8", + "@jupyterlab/htmlviewer-extension": "~4.0.8", + "@jupyterlab/hub-extension": "~4.0.8", + "@jupyterlab/imageviewer-extension": "~4.0.8", + "@jupyterlab/inspector-extension": "~4.0.8", + "@jupyterlab/javascript-extension": "~4.0.8", + "@jupyterlab/json-extension": "~4.0.8", + "@jupyterlab/launcher-extension": "~4.0.8", + "@jupyterlab/logconsole-extension": "~4.0.8", + "@jupyterlab/lsp-extension": "~4.0.8", + "@jupyterlab/mainmenu-extension": "~4.0.8", + "@jupyterlab/markdownviewer-extension": "~4.0.8", + "@jupyterlab/markedparser-extension": "~4.0.8", + "@jupyterlab/mathjax-extension": "~4.0.8", + "@jupyterlab/metadataform-extension": "~4.0.8", + "@jupyterlab/notebook-extension": "~4.0.8", + "@jupyterlab/pdf-extension": "~4.0.8", + "@jupyterlab/rendermime-extension": "~4.0.8", + "@jupyterlab/running-extension": "~4.0.8", + "@jupyterlab/settingeditor-extension": "~4.0.8", + "@jupyterlab/shortcuts-extension": "~4.0.8", + "@jupyterlab/statusbar-extension": "~4.0.8", + "@jupyterlab/terminal-extension": "~4.0.8", + "@jupyterlab/theme-dark-extension": "~4.0.8", + "@jupyterlab/theme-light-extension": "~4.0.8", + "@jupyterlab/toc-extension": "~6.0.8", + "@jupyterlab/tooltip-extension": "~4.0.8", + "@jupyterlab/translation-extension": "~4.0.8", + "@jupyterlab/ui-components-extension": "~4.0.8", + "@jupyterlab/vega5-extension": "~4.0.8" }, "devDependencies": { - "@jupyterlab/builder": "^3.6.6", - "@jupyterlab/buildutils": "^3.6.6", + "@jupyterlab/builder": "^4.0.8", + "@jupyterlab/buildutils": "^4.0.8", "chokidar": "^3.4.0", - "css-loader": "^5.0.1", + "css-loader": "^6.7.1", "duplicate-package-checker-webpack-plugin": "^3.0.0", - "file-loader": "~6.0.0", - "fs-extra": "^9.0.1", + "fs-extra": "^10.1.0", "glob": "~7.1.6", "handlebars": "^4.5.3", "html-loader": "~1.3.0", - "html-webpack-plugin": "^5.0.0-beta.6", - "license-webpack-plugin": "^2.3.14", - "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", + "html-webpack-plugin": "^5.5.0", + "license-webpack-plugin": "^4.0.2", + "mini-css-extract-plugin": "^2.7.0", + "mini-svg-data-uri": "^1.4.4", "rimraf": "~3.0.0", - "sort-package-json": "~1.44.0", + "sort-package-json": "~1.53.1", "source-map-loader": "~1.0.2", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "terser-webpack-plugin": "^4.1.0", - "url-loader": "~4.1.0", - "webpack": "^5.41.1", - "webpack-bundle-analyzer": "^3.6.0", - "webpack-cli": "^4.1.0", - "webpack-merge": "^5.1.2", + "style-loader": "~3.3.1", + "terser-webpack-plugin": "^5.3.7", + "webpack": "^5.76.1", + "webpack-bundle-analyzer": "^4.8.0", + "webpack-cli": "^5.0.1", + "webpack-merge": "^5.8.0", "whatwg-fetch": "^3.0.0", - "worker-loader": "^3.0.2", - "yarn-deduplicate": "^2.1.1" + "worker-loader": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" }, "jupyterlab": { "name": "JupyterLab", - "version": "3.6.6", + "version": "4.0.8", "extensions": { "@jupyterlab/application-extension": "", "@jupyterlab/apputils-extension": "", "@jupyterlab/cell-toolbar-extension": "", "@jupyterlab/celltags-extension": "", "@jupyterlab/codemirror-extension": "", - "@jupyterlab/collaboration-extension": "", "@jupyterlab/completer-extension": "", "@jupyterlab/console-extension": "", "@jupyterlab/csvviewer-extension": "", "@jupyterlab/debugger-extension": "", "@jupyterlab/docmanager-extension": "", - "@jupyterlab/docprovider-extension": "", "@jupyterlab/documentsearch-extension": "", "@jupyterlab/extensionmanager-extension": "", "@jupyterlab/filebrowser-extension": "", @@ -236,9 +235,12 @@ "@jupyterlab/inspector-extension": "", "@jupyterlab/launcher-extension": "", "@jupyterlab/logconsole-extension": "", + "@jupyterlab/lsp-extension": "", "@jupyterlab/mainmenu-extension": "", "@jupyterlab/markdownviewer-extension": "", - "@jupyterlab/mathjax2-extension": "", + "@jupyterlab/markedparser-extension": "", + "@jupyterlab/mathjax-extension": "", + "@jupyterlab/metadataform-extension": "", "@jupyterlab/notebook-extension": "", "@jupyterlab/rendermime-extension": "", "@jupyterlab/running-extension": "", @@ -251,8 +253,7 @@ "@jupyterlab/toc-extension": "", "@jupyterlab/tooltip-extension": "", "@jupyterlab/translation-extension": "", - "@jupyterlab/ui-components-extension": "", - "@jupyterlab/vdom-extension": "" + "@jupyterlab/ui-components-extension": "" }, "mimeExtensions": { "@jupyterlab/javascript-extension": "", @@ -260,40 +261,42 @@ "@jupyterlab/pdf-extension": "", "@jupyterlab/vega5-extension": "" }, - "externalExtensions": {}, "buildDir": "./static", "outputDir": ".", "singletonPackages": [ + "@codemirror/language", + "@codemirror/state", + "@codemirror/view", "@jupyter/ydoc", "@jupyterlab/application", "@jupyterlab/apputils", "@jupyterlab/cell-toolbar", "@jupyterlab/codeeditor", "@jupyterlab/codemirror", - "@jupyterlab/collaboration", "@jupyterlab/completer", "@jupyterlab/console", "@jupyterlab/coreutils", "@jupyterlab/debugger", "@jupyterlab/docmanager", - "@jupyterlab/docprovider", "@jupyterlab/documentsearch", "@jupyterlab/extensionmanager", "@jupyterlab/filebrowser", "@jupyterlab/fileeditor", + "@jupyterlab/htmlviewer", "@jupyterlab/imageviewer", "@jupyterlab/inspector", "@jupyterlab/launcher", "@jupyterlab/logconsole", + "@jupyterlab/lsp", "@jupyterlab/mainmenu", "@jupyterlab/markdownviewer", + "@jupyterlab/metadataform", "@jupyterlab/notebook", "@jupyterlab/rendermime", "@jupyterlab/rendermime-interfaces", "@jupyterlab/services", "@jupyterlab/settingeditor", "@jupyterlab/settingregistry", - "@jupyterlab/shared-models", "@jupyterlab/statedb", "@jupyterlab/statusbar", "@jupyterlab/terminal", @@ -301,14 +304,19 @@ "@jupyterlab/tooltip", "@jupyterlab/translation", "@jupyterlab/ui-components", + "@lezer/common", + "@lezer/highlight", "@lumino/algorithm", "@lumino/application", "@lumino/commands", "@lumino/coreutils", + "@lumino/datagrid", "@lumino/disposable", "@lumino/domutils", "@lumino/dragdrop", + "@lumino/keyboard", "@lumino/messaging", + "@lumino/polling", "@lumino/properties", "@lumino/signaling", "@lumino/virtualdom", @@ -326,13 +334,10 @@ "@jupyterlab/cell-toolbar": "../packages/cell-toolbar", "@jupyterlab/cell-toolbar-extension": "../packages/cell-toolbar-extension", "@jupyterlab/cells": "../packages/cells", - "@jupyterlab/celltags": "../packages/celltags", "@jupyterlab/celltags-extension": "../packages/celltags-extension", "@jupyterlab/codeeditor": "../packages/codeeditor", "@jupyterlab/codemirror": "../packages/codemirror", "@jupyterlab/codemirror-extension": "../packages/codemirror-extension", - "@jupyterlab/collaboration": "../packages/collaboration", - "@jupyterlab/collaboration-extension": "../packages/collaboration-extension", "@jupyterlab/completer": "../packages/completer", "@jupyterlab/completer-extension": "../packages/completer-extension", "@jupyterlab/console": "../packages/console", @@ -344,8 +349,6 @@ "@jupyterlab/debugger-extension": "../packages/debugger-extension", "@jupyterlab/docmanager": "../packages/docmanager", "@jupyterlab/docmanager-extension": "../packages/docmanager-extension", - "@jupyterlab/docprovider": "../packages/docprovider", - "@jupyterlab/docprovider-extension": "../packages/docprovider-extension", "@jupyterlab/docregistry": "../packages/docregistry", "@jupyterlab/documentsearch": "../packages/documentsearch", "@jupyterlab/documentsearch-extension": "../packages/documentsearch-extension", @@ -369,12 +372,16 @@ "@jupyterlab/launcher-extension": "../packages/launcher-extension", "@jupyterlab/logconsole": "../packages/logconsole", "@jupyterlab/logconsole-extension": "../packages/logconsole-extension", + "@jupyterlab/lsp": "../packages/lsp", + "@jupyterlab/lsp-extension": "../packages/lsp-extension", "@jupyterlab/mainmenu": "../packages/mainmenu", "@jupyterlab/mainmenu-extension": "../packages/mainmenu-extension", "@jupyterlab/markdownviewer": "../packages/markdownviewer", "@jupyterlab/markdownviewer-extension": "../packages/markdownviewer-extension", - "@jupyterlab/mathjax2": "../packages/mathjax2", - "@jupyterlab/mathjax2-extension": "../packages/mathjax2-extension", + "@jupyterlab/markedparser-extension": "../packages/markedparser-extension", + "@jupyterlab/mathjax-extension": "../packages/mathjax-extension", + "@jupyterlab/metadataform": "../packages/metadataform", + "@jupyterlab/metadataform-extension": "../packages/metadataform-extension", "@jupyterlab/metapackage": "../packages/metapackage", "@jupyterlab/nbconvert-css": "../packages/nbconvert-css", "@jupyterlab/nbformat": "../packages/nbformat", @@ -393,13 +400,13 @@ "@jupyterlab/settingeditor": "../packages/settingeditor", "@jupyterlab/settingeditor-extension": "../packages/settingeditor-extension", "@jupyterlab/settingregistry": "../packages/settingregistry", - "@jupyterlab/shared-models": "../packages/shared-models", "@jupyterlab/shortcuts-extension": "../packages/shortcuts-extension", "@jupyterlab/statedb": "../packages/statedb", "@jupyterlab/statusbar": "../packages/statusbar", "@jupyterlab/statusbar-extension": "../packages/statusbar-extension", "@jupyterlab/terminal": "../packages/terminal", "@jupyterlab/terminal-extension": "../packages/terminal-extension", + "@jupyterlab/testing": "../packages/testing", "@jupyterlab/theme-dark-extension": "../packages/theme-dark-extension", "@jupyterlab/theme-light-extension": "../packages/theme-light-extension", "@jupyterlab/toc": "../packages/toc", @@ -410,8 +417,6 @@ "@jupyterlab/translation-extension": "../packages/translation-extension", "@jupyterlab/ui-components": "../packages/ui-components", "@jupyterlab/ui-components-extension": "../packages/ui-components-extension", - "@jupyterlab/vdom": "../packages/vdom", - "@jupyterlab/vdom-extension": "../packages/vdom-extension", "@jupyterlab/vega5-extension": "../packages/vega5-extension", "@jupyterlab/builder": "../builder", "@jupyterlab/buildutils": "../buildutils", diff --git a/dev_mode/style.js b/dev_mode/style.js index b5fcc2e9cd3a..5897e2729046 100644 --- a/dev_mode/style.js +++ b/dev_mode/style.js @@ -12,7 +12,6 @@ import '@jupyterlab/console-extension/style/index.js'; import '@jupyterlab/csvviewer-extension/style/index.js'; import '@jupyterlab/debugger-extension/style/index.js'; import '@jupyterlab/docmanager-extension/style/index.js'; -import '@jupyterlab/docprovider-extension/style/index.js'; import '@jupyterlab/documentsearch-extension/style/index.js'; import '@jupyterlab/extensionmanager-extension/style/index.js'; import '@jupyterlab/filebrowser-extension/style/index.js'; @@ -26,9 +25,12 @@ import '@jupyterlab/javascript-extension/style/index.js'; import '@jupyterlab/json-extension/style/index.js'; import '@jupyterlab/launcher-extension/style/index.js'; import '@jupyterlab/logconsole-extension/style/index.js'; +import '@jupyterlab/lsp-extension/style/index.js'; import '@jupyterlab/mainmenu-extension/style/index.js'; import '@jupyterlab/markdownviewer-extension/style/index.js'; -import '@jupyterlab/mathjax2-extension/style/index.js'; +import '@jupyterlab/markedparser-extension/style/index.js'; +import '@jupyterlab/mathjax-extension/style/index.js'; +import '@jupyterlab/metadataform-extension/style/index.js'; import '@jupyterlab/notebook-extension/style/index.js'; import '@jupyterlab/pdf-extension/style/index.js'; import '@jupyterlab/rendermime-extension/style/index.js'; @@ -41,5 +43,4 @@ import '@jupyterlab/toc-extension/style/index.js'; import '@jupyterlab/tooltip-extension/style/index.js'; import '@jupyterlab/translation-extension/style/index.js'; import '@jupyterlab/ui-components-extension/style/index.js'; -import '@jupyterlab/vdom-extension/style/index.js'; import '@jupyterlab/vega5-extension/style/index.js'; diff --git a/dev_mode/templates/403.html b/dev_mode/templates/403.html index 315515710e72..34a495a1a308 100644 --- a/dev_mode/templates/403.html +++ b/dev_mode/templates/403.html @@ -1,3 +1,8 @@ + + diff --git a/dev_mode/templates/partial.html b/dev_mode/templates/partial.html index a3f368eaea74..3c44af54c52b 100644 --- a/dev_mode/templates/partial.html +++ b/dev_mode/templates/partial.html @@ -1,3 +1,8 @@ + + {# Copy so we do not modify the page_config with updates. #} {% set page_config_full = page_config.copy() %} diff --git a/dev_mode/templates/template.html b/dev_mode/templates/template.html index 167557d4fdda..6d17d790004d 100644 --- a/dev_mode/templates/template.html +++ b/dev_mode/templates/template.html @@ -1,3 +1,8 @@ + + diff --git a/dev_mode/webpack.config.js b/dev_mode/webpack.config.js index 5584aa2ab96c..4beb160bb68d 100644 --- a/dev_mode/webpack.config.js +++ b/dev_mode/webpack.config.js @@ -1,7 +1,7 @@ -/* ----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ const path = require('path'); const fs = require('fs-extra'); @@ -9,8 +9,8 @@ const Handlebars = require('handlebars'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); const merge = require('webpack-merge').default; -const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') - .BundleAnalyzerPlugin; +const BundleAnalyzerPlugin = + require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base'); const { ModuleFederationPlugin } = webpack.container; @@ -20,21 +20,7 @@ const packageData = require('./package.json'); // Handle the extensions. const jlab = packageData.jupyterlab; -const { extensions, mimeExtensions, externalExtensions } = jlab; - -// Add external extensions to the extensions/mimeExtensions data as -// appropriate -for (const pkg in externalExtensions) { - const { - jupyterlab: { extension, mimeExtension } - } = require(`${pkg}/package.json`); - if (extension !== undefined) { - extensions[pkg] = extension === true ? '' : extension; - } - if (mimeExtension !== undefined) { - mimeExtensions[pkg] = mimeExtension === true ? '' : mimeExtension; - } -} +const { extensions, mimeExtensions } = jlab; // Deduplicated list of extension package names. const extensionPackages = [ @@ -299,15 +285,14 @@ module.exports = [ output: { path: path.resolve(buildDir), publicPath: '{{page_config.fullStaticUrl}}/', - filename: '[name].[contenthash].js', - hashFunction: 'sha256' + filename: '[name].[contenthash].js' }, optimization: { splitChunks: { chunks: 'all', cacheGroups: { jlab_core: { - test: /[\\/]node_modules[\\/]@(jupyterlab|lumino)[\\/]/, + test: /[\\/]node_modules[\\/]@(jupyterlab|lumino(?!\/datagrid))[\\/]/, name: 'jlab_core' } } @@ -324,7 +309,7 @@ module.exports = [ ] }, devtool: 'inline-source-map', - externals: ['node-fetch', 'ws'], + externals: ['ws'], plugins }) ].concat(extensionAssetConfig); diff --git a/dev_mode/webpack.prod.config.js b/dev_mode/webpack.prod.config.js index a6b08a71b569..025b532242b8 100644 --- a/dev_mode/webpack.prod.config.js +++ b/dev_mode/webpack.prod.config.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const merge = require('webpack-merge').default; const config = require('./webpack.config'); const WPPlugin = require('@jupyterlab/builder').WPPlugin; diff --git a/dev_mode/webpack.prod.minimize.config.js b/dev_mode/webpack.prod.minimize.config.js index b107e5384031..0356d9b7b811 100644 --- a/dev_mode/webpack.prod.minimize.config.js +++ b/dev_mode/webpack.prod.minimize.config.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const TerserPlugin = require('terser-webpack-plugin'); const merge = require('webpack-merge').default; const WPPlugin = require('@jupyterlab/builder').WPPlugin; @@ -16,7 +21,6 @@ config[0] = merge(config[0], { minimizer: [ new TerserPlugin({ parallel: true, - sourceMap: true, terserOptions: { compress: false, ecma: 6, @@ -26,8 +30,7 @@ config[0] = merge(config[0], { comments: false }, safari10: true - }, - cache: process.platform !== 'win32' + } }) ] }, diff --git a/dev_mode/webpack.prod.release.config.js b/dev_mode/webpack.prod.release.config.js index 1b31286b7bc0..f48a3e70c403 100644 --- a/dev_mode/webpack.prod.release.config.js +++ b/dev_mode/webpack.prod.release.config.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const merge = require('webpack-merge').default; const config = require('./webpack.prod.minimize.config'); diff --git a/docs/Makefile b/docs/Makefile index 8d7f39c85afa..b02d18832b5e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,3 +1,6 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + # Minimal makefile for Sphinx documentation # @@ -21,5 +24,5 @@ help: clean: # clean api build as well - -rm -rf "$(SOURCEDIR)/../api" + -rm -rf "$(SOURCEDIR)/api" @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/environment.yml b/docs/environment.yml deleted file mode 100644 index a3d79cb39de5..000000000000 --- a/docs/environment.yml +++ /dev/null @@ -1,16 +0,0 @@ - -name: jupyterlab_documentation -channels: - - conda-forge -dependencies: -- python=3.8 -- sphinx>=1.8 -- sphinx-copybutton -- sphinx_rtd_theme -- pytest -- pytest-tornasync -- pytest-check-links -- pip -- nodejs=18 -- jsx-lexer -- myst-parser diff --git a/docs/make.bat b/docs/make.bat index 6814d9f111ef..786206f0cd66 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,3 +1,6 @@ +rem Copyright (c) Jupyter Development Team. +rem Distributed under the terms of the Modified BSD License. + @ECHO OFF pushd %~dp0 diff --git a/docs/scripts/graph-dependencies.js b/docs/scripts/graph-dependencies.js deleted file mode 100644 index 3fae9bd9ac9e..000000000000 --- a/docs/scripts/graph-dependencies.js +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -/** - * This script generates a transitive reduction of the dependency graph among - * jupyterlab packages using the graphviz library. It works from package.json - * dependencies, so does not capture the nuances of how plugins depend on each - * other, such as optional dependencies. Still, it can be useful to have a way - * to generate such a graph to get an idea of how packages depend on other - * packages. - * - * You must have graphviz installed to run this script. Run from the docs - * directory: - * - * % node scripts/graph-dependencies.js - */ - -const childProcess = require('child_process'); -const fs = require('fs-extra'); -const glob = require('glob'); -const path = require('path'); -const url = require('url'); - -const basePath = path.resolve('..'); -const baseUrl = 'https://github.com/jupyterlab/jupyterlab/tree/master/packages'; -const packages = glob.sync(path.join(basePath, 'packages/*')); - -// Begin the graph specification -let text = ['digraph G {', 'node [shape=box];']; - -packages.forEach(function (packagePath) { - // Load the package.json data. - const dataPath = path.join(packagePath, 'package.json'); - let data; - try { - data = require(dataPath); - } catch (e) { - return; - } - - const name = data.name ?? 'UNKNOWN'; - - // Don't include private packages. - if (data.private === true) { - return; - } - - // Only include packages in the @jupyterlab namespace. - if (!name.startsWith('@jupyterlab')) { - return; - } - - // In order to cut down on the number of graph nodes, - // don't include "*-extension" packages. - if (name.endsWith('-extension')) { - return; - } - - // Don't include the metapackage. - if (name === '@jupyterlab/metapackage') { - return; - } - - const shortName = name.split('/')[1]; - const urlLink = url.resolve( - baseUrl, - 'packages/' + path.basename(packagePath) - ); - - // Remove the '@jupyterlab' part of the name. - text.push(`"${shortName}" [URL="${urlLink}"];\n`); - - const deps = data.dependencies ?? []; - for (let dep in deps) { - // Only include JupyterLab dependencies - if (dep.startsWith('@jupyterlab')) { - text.push(`"${shortName}" -> "${dep.split('/')[1]}";\n`); - } - } -}); - -text.push('}'); - -fs.writeFileSync('./dependencies.gv', text.join('\n')); -childProcess.execSync( - 'cat dependencies.gv | tred | dot -Tsvg -o dependency-graph.svg' -); -fs.unlinkSync('./dependencies.gv'); diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css index ef54a5a6d812..7b1665fb9f90 100644 --- a/docs/source/_static/css/custom.css +++ b/docs/source/_static/css/custom.css @@ -1,22 +1,31 @@ -h4 { - font-size: 100%; +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +/* stylelint-disable selector-max-type */ + +/* Navbar at the top */ +.jupyter-nav-logo { + padding: 0; } -.wy-nav-side p.caption { - color: #f5f5f5; +.jupyter-nav-logo img { + width: 30px; } -div.wy-side-nav-search { - background: #f37626; +.navbar-brand { + padding: 0.6em; } -.wy-nav-content iframe { - margin: auto; - display: block; +/* Save some space by making this just long enough for the text */ +nav.navbar form.bd-search { + width: 14em; } -.wy-breadcrumbs-aside img { - height: 1em !important; +/* Text on page */ +h4 { + font-size: 100%; } /* Elevation @@ -27,38 +36,45 @@ div.wy-side-nav-search { * https://material-components-web.appspot.com/elevation.html */ -.rst-content img.jp-screenshot { +main img.jp-screenshot { border: none; + /* MD Elevation 8 */ - box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), - 0px 8px 10px 1px rgba(145, 145, 145, 0.14), - 0px 3px 14px 2px rgba(0, 0, 0, 0.12); + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(145, 145, 145, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); margin-bottom: 24px; } -/* +/* * The div.jp-youtube-video styling is done to get the YouTube video to size dynamically * to 100% of the content width. */ -.rst-content div.jp-youtube-video { +main div.jp-youtube-video { position: relative; width: 100%; - height: 0px; + height: 0; + /* This must be equal to the inverse of the aspect ratio of the video */ + /* The current value is: 56.25% = 315/560 */ padding-bottom: 56.25%; border: none; + /* MD Elevation 8 */ - box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), - 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12); + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); margin-bottom: 24px; } -.rst-content div.jp-youtube-video iframe { +main div.jp-youtube-video iframe { position: absolute; - left: 0px; - top: 0px; + left: 0; + top: 0; width: 100%; height: 100%; } diff --git a/docs/source/_static/logo-icon.png b/docs/source/_static/logo-icon.png new file mode 100644 index 000000000000..a65b84f94cfb Binary files /dev/null and b/docs/source/_static/logo-icon.png differ diff --git a/docs/source/_static/logo-rectangle-dark.svg b/docs/source/_static/logo-rectangle-dark.svg new file mode 100644 index 000000000000..d3e4b7eb50a1 --- /dev/null +++ b/docs/source/_static/logo-rectangle-dark.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/docs/source/_static/logo-rectangle.svg b/docs/source/_static/logo-rectangle.svg new file mode 100644 index 000000000000..e021cad426b2 --- /dev/null +++ b/docs/source/_static/logo-rectangle.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/docs/source/_static/switcher.json b/docs/source/_static/switcher.json new file mode 100644 index 000000000000..7d4bcf28267e --- /dev/null +++ b/docs/source/_static/switcher.json @@ -0,0 +1,57 @@ +[ + { + "name": "latest", + "version": "latest", + "url": "https://jupyterlab.readthedocs.io/en/latest/" + }, + { + "name": "stable", + "version": "stable", + "url": "https://jupyterlab.readthedocs.io/en/stable/" + }, + { + "name": "3.6.x", + "version": "3.6.x", + "url": "https://jupyterlab.readthedocs.io/en/3.6.x/" + }, + { + "name": "3.5.x", + "version": "3.5.x", + "url": "https://jupyterlab.readthedocs.io/en/3.5.x/" + }, + { + "name": "3.4.x", + "version": "3.4.x", + "url": "https://jupyterlab.readthedocs.io/en/3.4.x/" + }, + { + "name": "3.3.x", + "version": "3.3.x", + "url": "https://jupyterlab.readthedocs.io/en/3.3.x/" + }, + { + "name": "3.2.x", + "version": "3.2.x", + "url": "https://jupyterlab.readthedocs.io/en/3.2.x/" + }, + { + "name": "3.1.x", + "version": "3.1.x", + "url": "https://jupyterlab.readthedocs.io/en/3.1.x/" + }, + { + "name": "3.0.x", + "version": "3.0.x", + "url": "https://jupyterlab.readthedocs.io/en/3.0.x/" + }, + { + "name": "2.2.x", + "version": "2.2.x", + "url": "https://jupyterlab.readthedocs.io/en/2.2.x/" + }, + { + "name": "1.2.x", + "version": "1.2.x", + "url": "https://jupyterlab.readthedocs.io/en/1.2.x/" + } +] diff --git a/docs/source/_templates/breadcrumbs.html b/docs/source/_templates/breadcrumbs.html deleted file mode 100644 index 6bb97b377742..000000000000 --- a/docs/source/_templates/breadcrumbs.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends '!breadcrumbs.html' %} - -{% block breadcrumbs %} -
  • {{ _('Docs') }} »
  • - {% for doc in parents %} -
  • {{ doc.title }} »
  • - {% endfor %} -
  • {{ title }}
  • -{% endblock %} - {% block breadcrumbs_aside %} -
  • - {% if hasdoc(pagename) %} - {% if display_github %} - {% if check_meta and 'github_url' in meta %} - - {{ _('Edit on GitHub') }} - {% else %} - {{ _('Edit on GitHub') }} - {% endif %} - {% elif display_bitbucket %} - {% if check_meta and 'bitbucket_url' in meta %} - - {{ _('Edit on Bitbucket') }} - {% else %} - {{ _('Edit on Bitbucket') }} - {% endif %} - {% elif display_gitlab %} - {% if check_meta and 'gitlab_url' in meta %} - - {{ _('Edit on GitLab') }} - {% else %} - {{ _('Edit on GitLab') }} - {% endif %} - {% elif show_source and source_url_prefix %} - {{ _('View page source') }} - {% elif show_source and has_source and sourcename %} - {{ _('View page source') }} - {% endif %} - {% endif %} -
  • -
  • - - - {{ _('Jupyter') }} - - | -   -
  • -{% endblock %} diff --git a/docs/source/_templates/copyright.html b/docs/source/_templates/copyright.html new file mode 100644 index 000000000000..5f2bd71d5bf2 --- /dev/null +++ b/docs/source/_templates/copyright.html @@ -0,0 +1,36 @@ + + +
    +

    + {%- if show_copyright %} + {%- if hasdoc('copyright') %} + {% trans path=pathto('copyright'), copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} + {%- else %} + {% trans copyright=copyright|e %}© Copyright {{ copyright }}.
    + The Jupyter Trademark is registered with the U.S. Patent & Trademark Office. + {% endtrans %} + {%- endif %} + {%- endif %} + + {%- if build_id and build_url %} + {% trans build_url=build_url, build_id=build_id %} + + Build + {{ build_id }}. + + {% endtrans %} + {%- elif commit %} + {% trans commit=commit %} + + Revision {{ commit }}. + + {% endtrans %} + {%- elif last_updated %} + {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} + {%- endif %} + +

    +
    diff --git a/docs/source/_templates/footer.html b/docs/source/_templates/footer.html deleted file mode 100644 index b91bf2705e11..000000000000 --- a/docs/source/_templates/footer.html +++ /dev/null @@ -1,54 +0,0 @@ -
    - {% if (theme_prev_next_buttons_location == 'bottom' or theme_prev_next_buttons_location == 'both') and (next or prev) %} - - {% endif %} - -
    - -
    -

    - {%- if show_copyright %} - {%- if hasdoc('copyright') %} - {% trans path=pathto('copyright'), copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} - {%- else %} - {% trans copyright=copyright|e %}© Copyright {{ copyright }}.
    - The Jupyter Trademark is registered with the U.S. Patent & Trademark Office. - {% endtrans %} - {%- endif %} - {%- endif %} - - {%- if build_id and build_url %} - {% trans build_url=build_url, build_id=build_id %} - - Build - {{ build_id }}. - - {% endtrans %} - {%- elif commit %} - {% trans commit=commit %} - - Revision {{ commit }}. - - {% endtrans %} - {%- elif last_updated %} - {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} - {%- endif %} - -

    -
    - - {%- if show_sphinx %} - {% trans %}Built with Sphinx using a theme provided by Read the Docs{% endtrans %}. - {%- endif %} - - {%- block extrafooter %} {% endblock %} - -
    - diff --git a/docs/source/conf.py b/docs/source/conf.py index b5b56807fbc3..74b9ced12d62 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + # # JupyterLab documentation build configuration file, created by # sphinx-quickstart on Thu Jan 4 15:10:23 2018. @@ -21,12 +23,17 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) +import json import os -import os.path as osp import shutil +import time +from collections import ChainMap +from functools import partial +from pathlib import Path from subprocess import check_call +from typing import List -HERE = osp.abspath(osp.dirname(__file__)) +HERE = Path(__file__).parent.resolve() # -- General configuration ------------------------------------------------ @@ -37,7 +44,12 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ["myst_parser", "sphinx.ext.intersphinx", "sphinx.ext.mathjax", "sphinx_copybutton"] +extensions = [ + "myst_parser", + "sphinx.ext.intersphinx", + "sphinx.ext.mathjax", + "sphinx_copybutton", +] myst_enable_extensions = ["html_image"] myst_heading_anchors = 3 @@ -55,7 +67,7 @@ # General information about the project. project = "JupyterLab" -copyright = "2018, Project Jupyter" +copyright = f"2018-{time.localtime().tm_year}, Project Jupyter" # noqa author = "Project Jupyter" @@ -63,14 +75,13 @@ # |version| and |release|, also used in various other places throughout the # built documents. -_version_py = osp.join(HERE, "..", "..", "jupyterlab", "_version.py") +_version_py = HERE.parent.parent / "jupyterlab" / "_version.py" version_ns = {} -with open(_version_py, mode="r") as version_file: - exec(version_file.read(), version_ns) +exec(_version_py.read_text(), version_ns) # noqa # The short X.Y version. -version = "%i.%i" % version_ns["version_info"][:2] +version = "{0:d}.{1:d}".format(*version_ns["version_info"]) # noqa # The full version, including alpha/beta/rc tags. release = version_ns["__version__"] @@ -79,8 +90,10 @@ # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = "en" +language = "en" # Must be set from the command line to generate various languages + +locale_dirs = ["locale/"] +gettext_compact = False # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -92,31 +105,29 @@ # build js docs and stage them to the build directory -def build_api_docs(out_dir): +def build_api_docs(out_dir: Path): """build js api docs""" - docs = osp.join(HERE, os.pardir) - root = osp.join(docs, os.pardir) - docs_api = osp.join(docs, "api") - api_index = osp.join(docs_api, "index.html") + docs = HERE.parent + root = docs.parent + docs_api = docs / "source" / "api" + api_index = docs_api / "index.html" # is this an okay way to specify jlpm # without installing jupyterlab first? - jlpm = ["node", osp.join(root, "jupyterlab", "staging", "yarn.js")] + jlpm = ["node", str(root / "jupyterlab" / "staging" / "yarn.js")] - if osp.exists(api_index): + if api_index.exists(): # avoid rebuilding docs because it takes forever # `make clean` to force a rebuild - print(f"already have {api_index}") + pass else: - print("Building jupyterlab API docs") - check_call(jlpm, cwd=root) - check_call(jlpm + ["build:packages"], cwd=root) - check_call(jlpm + ["docs"], cwd=root) + check_call(jlpm, cwd=str(root)) # noqa S603 + check_call([*jlpm, "build:packages"], cwd=str(root)) # noqa S603 + check_call([*jlpm, "docs"], cwd=str(root)) # noqa S603 - dest_dir = osp.join(out_dir, "api") - print(f"Copying {docs_api} -> {dest_dir}") - if osp.exists(dest_dir): - shutil.rmtree(dest_dir) - shutil.copytree(docs_api, dest_dir) + dest_dir = out_dir / "api" + if dest_dir.exists(): + shutil.rmtree(str(dest_dir)) + shutil.copytree(str(docs_api), str(dest_dir)) # Copy frontend files for snippet inclusion @@ -126,16 +137,98 @@ def build_api_docs(out_dir): SNIPPETS_FOLDER = "snippets" -def copy_code_files(temp_folder): +def copy_code_files(temp_folder: Path): """Copy files in the temp_folder""" - docs = osp.join(HERE, os.pardir) - root = osp.join(docs, os.pardir) + docs = HERE.parent + root = docs.parent for file in FILES_LIST: - target = osp.join(temp_folder, file) - if not osp.exists(osp.dirname(target)): - os.makedirs(osp.dirname(target), exist_ok=True) - shutil.copyfile(osp.join(root, file), target) + target = temp_folder / file + if not target.parent.exists(): + target.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(str(root / file), str(target)) + + # Split plugin schema to ease documentation maintenance + if file == "packages/settingregistry/src/plugin-schema.json": + schema = json.loads(Path(target).read_text()) + + partial_schema = ChainMap(schema.get("definitions", {}), schema.get("properties", {})) + for key in partial_schema: + fragment = target.parent / f"{key}.json" + with fragment.open("w") as f: + json.dump({key: partial_schema[key]}, f, indent=2) + + +IMAGES_FOLDER = "images" +AUTOMATED_SCREENSHOTS_FOLDER = "galata/test/documentation" + + +def copy_automated_screenshots(temp_folder: Path) -> List[Path]: + """Copy PlayWright automated screenshots in documentation folder. + + Args: + temp_folder: Target directory in which to copy the file + Returns: + List of copied files + """ + docs = HERE.parent + root = docs.parent + + src = root / AUTOMATED_SCREENSHOTS_FOLDER + + copied_files = [] + for img in src.rglob("*.png"): + target = temp_folder / (img.name.replace("-documentation-linux", "")) + shutil.copyfile(str(img), str(target)) + copied_files.append(target) + + return copied_files + + +COMMANDS_LIST_PATH = "commands.test.ts-snapshots/commandsList-documentation-linux.json" +COMMANDS_LIST_DOC = "user/commands_list.md" +PLUGINS_LIST_PATH = "plugins.test.ts-snapshots/plugins-documentation-linux.json" +PLUGINS_LIST_DOC = "extension/plugins_list.rst" +TOKENS_LIST_PATH = "plugins.test.ts-snapshots/tokens-documentation-linux.json" +TOKENS_LIST_DOC = "extension/tokens_list.rst" + + +def document_commands_list(temp_folder: Path) -> None: + """Generate the command list documentation page from application extraction.""" + list_path = HERE.parent.parent / AUTOMATED_SCREENSHOTS_FOLDER / COMMANDS_LIST_PATH + + commands_list = json.loads(list_path.read_text()) + + template = """| Command id | Label | Shortcuts | +| ---------- | ----- | --------- | +""" + + for command in sorted(commands_list, key=lambda c: c["id"]): + for key in ("id", "label", "caption"): + if key not in command: + command[key] = "" + else: + command[key] = command[key].replace("\n", " ") + shortcuts = command.get("shortcuts", []) + command["shortcuts"] = ( + "" + ", ".join(shortcuts) + "" if len(shortcuts) else "" + ) + + template += "| `{id}` | {label} | {shortcuts} |\n".format(**command) + + (temp_folder / COMMANDS_LIST_DOC).write_text(template) + + +def document_plugins_tokens_list(list_path: Path, output_path: Path) -> None: + """Generate the plugins list documentation page from application extraction.""" + items = json.loads(list_path.read_text()) + + template = "" + + for _name, _description in items.items(): + template += f"- ``{_name}``: {_description}\n" + + output_path.write_text(template) # -- Options for HTML output ---------------------------------------------- @@ -143,16 +236,56 @@ def copy_code_files(temp_folder): # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -import sphinx_rtd_theme - -html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - +html_theme = "pydata_sphinx_theme" +html_logo = "_static/logo-rectangle.svg" +html_favicon = "_static/logo-icon.png" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # -# html_theme_options = {} +html_theme_options = { + "icon_links": [ + { + "name": "jupyter.org", + "url": "https://jupyter.org", + "icon": "_static/jupyter_logo.svg", + "type": "local", + }, + { + "name": "GitHub", + "url": "https://github.com/jupyterlab/jupyterlab", + "icon": "fab fa-github-square", + }, + { + "name": "Discourse", + "url": "https://discourse.jupyter.org/c/jupyterlab/17", + "icon": "fab fa-discourse", + }, + { + "name": "Gitter", + "url": "https://gitter.im/jupyterlab/jupyterlab", + "icon": "fab fa-gitter", + }, + ], + "logo": { + "image_light": "_static/logo-rectangle.svg", + "image_dark": "_static/logo-rectangle-dark.svg", + "alt_text": "JupyterLab", + }, + "use_edit_page_button": True, + "navbar_align": "left", + "navbar_start": ["navbar-logo", "version-switcher"], + "navigation_with_keys": False, + "footer_start": ["copyright.html"], + "switcher": { + # Trick to get the documentation version switcher to always points to the latest version without being corrected by the integrity check; + # otherwise older versions won't list newer versions + "json_url": "/".join( + ("https://jupyterlab.readthedocs.io/en", "latest", "_static/switcher.json") + ), + "version_match": os.environ.get("READTHEDOCS_VERSION", "latest"), + }, +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -165,22 +298,16 @@ def copy_code_files(temp_folder): # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { - "**": [ - "about.html", - "navigation.html", - "relations.html", # needs 'show_related': True theme option to display - "searchbox.html", - "donate.html", - ] + "index": [], # Home page has no sidebar so there's more room for content + "**": ["sidebar-nav-bs.html"], } # Output for github to be used in links html_context = { - "display_github": True, # Integrate GitHub "github_user": "jupyterlab", # Username "github_repo": "jupyterlab", # Repo name - "github_version": "3.6.x", # Version - "conf_py_path": "/docs/source/", # Path in the checkout to the docs root + "github_version": "4.0.x", # Version + "doc_path": "docs/source/", # Path in the checkout to the docs root } # -- Options for HTMLHelp output ------------------------------------------ @@ -210,7 +337,13 @@ def copy_code_files(temp_folder): # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "JupyterLab.tex", "JupyterLab Documentation", "Project Jupyter", "manual"), + ( + master_doc, + "JupyterLab.tex", + "JupyterLab Documentation", + "Project Jupyter", + "manual", + ), ] @@ -265,18 +398,36 @@ def copy_code_files(temp_folder): def setup(app): - dest = osp.join(HERE, "getting_started/changelog.md") - shutil.copy(osp.join(HERE, "..", "..", "CHANGELOG.md"), dest) + dest = HERE / "getting_started/changelog.md" + shutil.copy(str(HERE.parent.parent / "CHANGELOG.md"), str(dest)) app.add_css_file("css/custom.css") # may also be an URL - build_api_docs(app.outdir) + # Skip we are dealing with internationalization + outdir = Path(app.outdir) + if outdir.name != "gettext": + build_api_docs(outdir) - copy_code_files(osp.join(app.srcdir, SNIPPETS_FOLDER)) + copy_code_files(Path(app.srcdir) / SNIPPETS_FOLDER) + tmp_files = copy_automated_screenshots(Path(app.srcdir) / IMAGES_FOLDER) - def clean_code_files(app, exception): + def clean_code_files(tmp_files, app, exception): """Remove temporary folder.""" try: - shutil.rmtree(osp.join(app.srcdir, SNIPPETS_FOLDER)) - except Exception as e: - print(f"Fail to remove temporary snippet folder: {e}") - - app.connect("build-finished", clean_code_files) + shutil.rmtree(str(Path(app.srcdir) / SNIPPETS_FOLDER)) + except Exception: # noqa S110 + pass + + for f in tmp_files: + f.unlink() + + src_dir = Path(app.srcdir) + document_commands_list(src_dir) + document_plugins_tokens_list( + HERE.parent.parent / AUTOMATED_SCREENSHOTS_FOLDER / PLUGINS_LIST_PATH, + src_dir / PLUGINS_LIST_DOC, + ) + document_plugins_tokens_list( + HERE.parent.parent / AUTOMATED_SCREENSHOTS_FOLDER / TOKENS_LIST_PATH, + src_dir / TOKENS_LIST_DOC, + ) + + app.connect("build-finished", partial(clean_code_files, tmp_files)) diff --git a/docs/source/developer/accessibility.rst b/docs/source/developer/accessibility.rst new file mode 100644 index 000000000000..f78dcbeb85ff --- /dev/null +++ b/docs/source/developer/accessibility.rst @@ -0,0 +1,274 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + +Accessibility: A JupyterLab Developer's Guide +============================================= + +If you're making changes to the JupyterLab source code and you're concerned +about `accessibility `__, this page +is for you. + +Looking for other ways to `contribute to accessibility on Jupyter projects +`__? + +Where to start +-------------- + +Thank you for being interested in improving JupyterLab's accessibility. Whether +making accessibility-specific fixes or considering the accessibility impacts of +another contribution, your work betters JupyterLab for everyone who uses it. + +A common question when accessibility-minded developers come to JupyterLab is: +where do I get started? + +If you don't have a lot of time to immerse yourself in the big picture of +JupyterLab accessibility work, then the GitHub issues labeled `good first issue +and accessibility +`__ +are a good place to start. + +If you want to more fully immerse yourself in the work of making JupyterLab (or +other Jupyter projects) more accessible, then a good place to start would be to +join the `Jupyter accessibility meeting +`__ +that happens every other week. If you cannot attend the call, you can peruse the +meeting notes and find links to other resources on the `Jupyter Accessibility +`__ site. + +Looking for a `frontend developer's orientation to the JupyterLab codebase +`__? + +Best practices while developing +------------------------------- + +JupyterLab is a web application and authoring tool. Therefore the following +standards apply: + +- WCAG - `Web Content Accessibility Guidelines + `__ +- ARIA - `Accessible Rich Internet Applications + `__ +- ATAG - `Authoring Tool Accessibility Guidelines + `__ + +These are good places to familiarize yourself with accessibility best practices +for developing websites (WCAG) and web applications (ARIA). Note that although +WCAG was created primarily for static websites, the guidelines are nonetheless +applicable to web apps like JupyterLab. + +One resource that is often particularly helpful for developers looking for +examples and best practices is `ARIA Patterns +`__. This web resource contains +examples of how to implement UI elements—such as menus, dialogs, breadcrumbs, +and more—in a more accessible way. However, be careful! Just because you can +implement a button using divs and aria attributes does not mean that you should! +(Most likely you should just use the button tag.) As a best practice, you should +only use ARIA when you cannot use existing HTML elements (button, input, nav, +aside, etc.) to achieve the UX that you desire. + +Finally, there is much more accessibility knowledge on the Internet than there +is in JupyterLab or Project Jupyter alone. Whatever you decide to work on, +consider exploring accessibility resources in other spaces for similar or +equivalent efforts. Accessibility communities tend to be generous with the +resources they provide to improve web accessibility. Many times, searching for +the name of the task or issue appended with `accessibility` in a search engine +will give you several results and a chance to learn from the broader community +right away. + +The rest of this section contains best practices specific to JupyterLab and its +development. + +Use color variables from the CSS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When fixing contrast or other visual accessibility issues in JupyterLab, it can +be tempting to pick a color and apply it to the part of the UI that you are +working on. However, it quickly becomes unmanageable to have color values spread +throughout the app across different CSS files. Therefore, the JupyterLab +codebase defines a set of `color variables +`__ +that can be used for borders, icons, and such. If you're adding any CSS that +needs a color value, please use one of the variables defined. + +Upstream fixes in Lumino +^^^^^^^^^^^^^^^^^^^^^^^^ + +JupyterLab uses a front-end framework that was built specifically for it called +Lumino. Lumino is similar in some ways to React, Vue, and Angular, but it also +provides a number of UI widgets like menu bars, tab bars, and dock panels. As a +result, some of the accessibility issues reported in the JupyterLab GitHub repo +need to be fixed in the Lumino repo. A good resource for learning Lumino: +`PhosphorJS (now Lumino) Mentor Sessions +`__. +PhosphorJS was Lumino's previous name. There is a page with `notes from the +PhosphorJS sessions +`__ that +also has a link to some additional videos that were not uploaded to YouTube. + +It's not always obvious when an accessibility issue should be fixed in +JupyterLab or Lumino. Some guidance to help you identify where your change +should be made: + +- Generally speaking, if you can fix the issue in Lumino, it's better to fix it + in Lumino because then the fix will be absorbed in more places. +- However, for that same reason, because Lumino is used by more codebases than + just JupyterLab—specifically, by JupyterLab extensions—one should be careful + making changes to Lumino that might break downstream consumers/extensions. +- So an additional rule of thumb is: if you can't make the fix in Lumino without + breaking dependants, then it might be better to make the fix in JupyterLab. In + this case, you might take a two-track approach, where you fix the + accessibility issue in JupyterLab and also submit a breaking fix in Lumino + that targets a future, major, API-breaking release/version of Lumino. + +Automated Regression Testing +---------------------------- + +If you fix an accessibility issue in the source code but you don't add a test +with your fix, then there's a strong chance that your fix will be undone +accidentally by some future changes to the codebase. + +Sometimes it's straightforward to unit-test an accessibility fix, such as when +`enabling keyboard shortcuts on a toolbar button +`__. But often it's +difficult to unit-test accessibility fixes. + +Therefore there is an effort underway to use `Playwright +`__ to write user-level `accessibility tests to +JupyterLab +`__. +To illustrate how to use it within your development process, let's walk through +an example. + +This example will involve three separate GitHub repos: + +1. `Quansight-Labs/jupyter-a11y-testing + `__ +2. `jupyterlab/lumino `__ +3. `jupyterlab/jupyterlab `__ + +This is a real world example, taken from actual past work. + +Let's say you do an accessibility audit of the start page of the JupyterLab UI +and find a tab trap in the top menu bar, meaning the user can press the tab key +to get into the menu bar but cannot easily get past it using only the keyboard. + +You dig in further and discover that the `tab trap bug is in the +jupyterlab/lumino repo `__, so +you fork the jupyterlab/lumino repo, create a new branch called +``fix-tab-trap``, and open a pull request. + +You decide that you want to write a test. This is one of those cases where writing a unit test would be a straightforward task. However, a unit test would only check the +top menu bar, so it would not prevent a reappearance of the issue that you +decided you want to fix once and for all, namely: you don't want any tab traps +anywhere on the JupyterLab start page. + +So you decide that you want to `add a regression test to the +Quansight-Labs/jupyter-a11y-testing repo +`__. +This test checks that there are no tab traps on the JupyterLab start page by +using Playwright to open JupyterLab and press the tab key repeatedly. So as with +the Lumino repo before, you fork the Quansight-Labs/jupyter-a11y-testing repo, +create a branch called ``test-tab-trap``, and open a pull request. The important +thing in this step is that you save your test file with a ``.test.ts`` extension +next to the other regression test files. + +Now you want to run your test. Specifically, you want to run the test against a +build of JupyterLab that incorporates your Lumino fix. Here's how you would do +that. + +Let's pretend that your GitHub username is *a11ydev* and you've forked the +Lumino and testing repos and created the following branches on those forks, one +with your bug fix and the other with your test: + +1. ``a11ydev/lumino:fix-tab-trap`` +2. ``a11ydev/jupyter-a11y-testing:test-tab-trap`` + +On GitHub, go to your fork of the testing repo, *a11ydev/jupyter-a11y-testing*. +Make sure that you are on your `test-tab-trap` branch, which contains the +``.test.ts`` file that you added. Then go to Actions and click on the workflow +titled "Run accessibility tests on JupyterLab." Click "Run workflow." This will +open a form to configure the workflow. + +Here's how you should fill out the form: + +1. Use workflow from: ``test-tab-trap`` +2. JupyterLab repo: ``jupyterlab/jupyterlab`` +3. Branch/tag/SHA: ``main`` +4. Test suite: leave blank +5. External package repo: ``a11ydev/lumino`` +6. External package ref: ``fix-tab-trap`` + +Then press the "Run workflow" button. A GitHub action should then build +JupyterLab from source, linking your Lumino fork and branch, then run the test +suite, including your test, and then finally show the test results, hopefully +with your test passing. + +Note that in this example you did not fork the jupyterlab/jupyterlab repo or +change the branch name to something other than "main" in the workflow config +form. This is because you did not need to modify the JupyterLab codebase to fix this issue. But if you were working on an issue that required you +to modify the JupyterLab codebase, you would do the same thing that you did +earlier with Lumino: fork the repo, create a branch with your fix, and then +enter your fork and branch in the workflow config form before running the +workflow. That should cause it to build a version of JupyterLab based on your +changes and then run the test suite against it. The workflow is flexible enough +to allow you to test against changes in JupyterLab or Lumino or both at the same +time if needed. + +.. note:: There are more `detailed instructions for how to use the GitHub workflow `__ in the testing repo. + +PR Review and Manual Testing +---------------------------- + +When reviewing code, documentation, or other contributions, you can use manual +testing to help prevent accessibility bugs. Typically you try and complete a +task related to your fix or contribution using an accessibility accommodation or +setting. Common options include: + +- Using a `screen reader `__. +- Zooming the page up to 400% via your browser. +- Unplugging or not using your mouse. Navigate only with the keyboard. +- `Emulating vision deficiencies + `__ + (Chrome, Edge, and Firefox all provide built-in tools to do this.) + +While testing, take note of what happens and compare it to what you can do to +complete the task without your chosen accessibility accommodation. If there is +anything you cannot complete, then you have a blocking accessibility issue. Even +though your use of assistive tech or an accessibility accommodation will likely +differ from someone who uses them regularly, knowing the results is helpful to +tell if JupyterLab is behaving as you expect. + +GitPod +^^^^^^ + +If you have a `GitPod `__ account and you have submitted +a PR to JupyterLab, you can manually test it by copying the GitHub URL to your +PR and concatenating it to ``gitpod.io/#``, like so: + +:samp:`https://gitpod.io/#https://github.com/jupyterlab/jupyterlab/pull/{your-pr-number}` + +GitPod will build JupyterLab from source with your PR applied and set up a +tunnel so that you can load the UI in your browser at localhost:8888. + +Useful tools for development +---------------------------- + +Here is a list of some apps that developers have found useful while doing +accessibility work in JupyterLab: + +- Chrome Dev Tools for `discovering and fixing low contrast text + `__ and + for `viewing the accessibility tree + `__ +- `Axe DevTools + `__, + extension for Chrome Dev Tools +- `Color Contrast Analyzer `__, + desktop app for Windows and Mac +- `Polypane `__, desktop browser with some dev tools + built in (note it's not free but it does have a free trial) +- `Axe Accessibility Linter + `__, + extension for VS Code +- GitPod: See the GitPod section under the Testing section above. +- And of course, screen readers such as JAWS, NVDA, and VoiceOver. diff --git a/docs/source/developer/api.rst b/docs/source/developer/api.rst index 126e9e178b89..e2b0937541aa 100644 --- a/docs/source/developer/api.rst +++ b/docs/source/developer/api.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + JupyterLab API Reference ======================== diff --git a/docs/source/developer/components.rst b/docs/source/developer/components.rst index c9f7cb81e565..243457692184 100644 --- a/docs/source/developer/components.rst +++ b/docs/source/developer/components.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + Using JupyterLab components =========================== @@ -8,7 +11,7 @@ IDE-like experience. However, developers are encouraged to use these to bring to life their own visions of what a computational environment should look like. -The JupyterLab repository has `many examples `_ +The JupyterLab repository has `many examples `_ to get you started. The ``examples`` directory contains: diff --git a/docs/source/developer/contributing.rst b/docs/source/developer/contributing.rst index b9c06c92e699..0889684ba229 100644 --- a/docs/source/developer/contributing.rst +++ b/docs/source/developer/contributing.rst @@ -1,5 +1,8 @@ -Contributing to JupyterLab -========================== +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + +Contribute +========== If you're reading this section, you're probably interested in contributing to JupyterLab. Welcome and thanks for your interest in @@ -7,10 +10,19 @@ contributing! Please take a look at the Contributor documentation, familiarize yourself with using JupyterLab, and introduce yourself to the community -(on the mailing list or discourse) and share what area of the project -you are interested in working on. Please also see the Jupyter `Community +(on the `chat `__ and/or the `forum `__) +and share what area of the project you are interested in working on. Please also see the Jupyter `Community Guides `__. +You can help make it better by: + +* `submitting bug reports `__, +* `proposing new features `__, +* `translating the application `__, +* `improving the documentation `__, +* improving the code base and fixing bug (see below) + + We have labeled some issues as `good first issue `__ or `help @@ -29,6 +41,18 @@ any Jupyter project, please report it to security@ipython.org. If you prefer to encrypt your security reports, you can use `this PGP public key `__. +.. toctree:: + :hidden: + + repo + components + patterns + Accessibility + internationalization + css + performance + api + .. contents:: Table of contents :local: :depth: 1 @@ -42,24 +66,69 @@ Documentation `__. +.. _versioning_notes: + +Backwards Compatibility, Versions and Breaking Changes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +New versions of JupyterLab may break backwards compatibility with extensions and other Jupyter +customizations. Breaking changes are kept to a minimum where possible. JupyterLab development +and release cycles follow `semantic versioning `__, so when breaking +changes are necessary, they are communicated via the version numbering scheme. In short, this +means that, for a JupyterLab version X.Y.Z: + +- Major version (X) number changes indicate breaking changes (NOT backwards compatible) +- Minor Version (Y) number changes indicate a backwards compatible addition of new features +- Patch version (Z) number changes indicate backwards compatible bug fixes + +Contributions to JupyterLab extensions and other customizations should plan for possible +breaking changes. Consider documenting your maintenance plans to users in these projects. +You may also wish to consider pinning the major version of JupyterLab when developing +extensions (in your package metadata). + We maintain the **two most recently released major versions of JupyterLab**, -JupyterLab v2 and JupyterLab v3. After JupyterLab v4 is released, we will no -longer maintain v2. +JupyterLab v3 and JupyterLab v4. JupyterLab v1 and v2 are no longer maintained. All JupyterLab v2 users are strongly advised to upgrade as soon as possible. +Languages, Tools and Processes +------------------------------ + All source code is written in `TypeScript `__. See the `Style Guide `__. -All source code is formatted using `prettier `__. +All non-python source code is formatted using `prettier `__, and python source code is formatted using `black `__. When code is modified and committed, all staged files will be -automatically formatted using pre-commit git hooks (with help from the -`lint-staged `__ and -`husky `__ libraries). The benefit of -using a code formatter like prettier is that it removes the topic of +automatically formatted using pre-commit git hooks (with help from +`pre-commit `__). The benefit of +using a code formatters like ``prettier`` and ``black`` is that it removes the topic of code style from the conversation when reviewing pull requests, thereby speeding up the review process. +As long as your code is valid, +the pre-commit hook should take care of how it should look. +`pre-commit` and its associated hooks will automatically be installed when +you run ``pip install -e ".[dev,test]"`` + +To install ``pre-commit`` manually, run the following:: + + pip install pre-commit + pre-commit install + +You can invoke the pre-commit hook by hand at any time with:: + + pre-commit run + +which should run any autoformatting on your code +and tell you about any errors it couldn't fix automatically. +You may also install `black integration `__ +into your text editor to format code automatically. + +If you have already committed files before setting up the pre-commit +hook with ``pre-commit install``, you can fix everything up using +``pre-commit run --all-files``. You need to make the fixing commit +yourself after that. + You may also use the prettier npm script (e.g. ``npm run prettier`` or ``yarn prettier`` or ``jlpm prettier``) to format the entire code base. We recommend installing a prettier extension for your code editor and @@ -70,18 +139,29 @@ Submitting a Pull Request Contribution -------------------------------------- Generally, an issue should be opened describing a piece of proposed work -and the issues it solves before a pull request is opened. A triager will +and the issues it solves before a pull request is opened. A triager will ensure that your issue meets our definition of ready before we can merge any pull requests that relate to it. +Pull requests must target the development branch (= ``main``) even if +it aims at addressing an issue seen in a stable release. Once the pull +request is merged on the development branch, it will be backported to +the stable branch using a bot action (or manually if the bot action +failed). + +.. note:: + + Don't hesitate to mention the targeted version in a PR description. + A maintainer will set the milestone accordingly. + Issue Management ^^^^^^^^^^^^^^^^ Opening an issue lets community members participate in the design discussion, makes others aware of work being done, and sets the stage -for a fruitful community interaction. When you open a new bug or -enhancement request, please provide all the requested information -in the issue template +for a fruitful community interaction. When you open a new bug or +enhancement request, please provide all the requested information +in the issue template so that a responder will be able to triage your bug without delay. A pull request should reference @@ -93,7 +173,7 @@ bot `__ will lock the issue. If additional discussion is desired, or if the pull request doesn't fully address the locked issue, please open a new issue referencing the locked issue. -New issues are subject to triage. A developer with triage permissions +New issues are subject to triage. A developer with triage permissions (a *triager*) will do the following: 1. Read the issue @@ -102,24 +182,24 @@ New issues are subject to triage. A developer with triage permissions 4. If the issue is ready to be worked on, assign it to a milestone 5. Apply appropriate labels to the issue (see examples below) -A developer may start to work on an issue as soon as it is filed. Please -work with a triager if they have any questions about your issue so that +A developer may start to work on an issue as soon as it is filed. Please +work with a triager if they have any questions about your issue so that your changes can be merged in without delay. Definition of Ready ^^^^^^^^^^^^^^^^^^^ One of the main goals of triage is to get issues into a state where they -are **ready** for someone to work on. Once a triager is satisfied that an +are **ready** for someone to work on. Once a triager is satisfied that an issue meets the definition below, they will remove the ``status:Needs Triage`` -label from it. We will not merge a pull request for an issue that still +label from it. We will not merge a pull request for an issue that still needs triage. -Triagers should also ensure that the issue has appropriate labels that -describe it, such as labels with the ``pkg:`` prefix for issues that +Triagers should also ensure that the issue has appropriate labels that +describe it, such as labels with the ``pkg:`` prefix for issues that affect one or more packages. -**All requested information, where applicable, is provided.** From the +**All requested information, where applicable, is provided.** From the templates in JupyterLab’s issues: For a **bug**: @@ -135,7 +215,7 @@ For a **feature request**: * Description of the proposed solution * Additional context -**The issue should represent real, relevant, feasible work**. In short, if a +**The issue should represent real, relevant, feasible work**. In short, if a knowledgeable person were to be assigned this issue, they would be able to complete it with a reasonable amount of effort and assistance, and it furthers the goals of the Jupyter project. @@ -144,9 +224,9 @@ furthers the goals of the Jupyter project. * Bugs represent valid expectations for use of Jupyter products and services. * Expectations for security, performance, accessibility, and localization match generally-accepted norms in the community that uses Jupyter products. -* The issue represents work that one developer can commit to owning, even if - they collaborate with other developers for feedback. Excessively large issues - should be split into multiple issues, each triaged individually, or into +* The issue represents work that one developer can commit to owning, even if + they collaborate with other developers for feedback. Excessively large issues + should be split into multiple issues, each triaged individually, or into `team-compass `__ issues to discuss more substantive changes. @@ -157,21 +237,32 @@ All new bugs and enhancement requests have the ``status:Needs Triage`` label. On a regular basis, Jupyter contributors (triage reviewers or triagers) review JupyterLab issues tagged -with ``status:Needs Triage``, starting with the oldest, and determine +with ``status:Needs Triage``, starting with the oldest, and determine whether they meet the definition of ready. -Once triaged, if the issue is ready, the reviewer removes the -``status:Needs Triage`` label; no additional label is required. If there +Once triaged, if the issue is ready, the reviewer removes the +``status:Needs Triage`` label; no additional label is required. If there is not enough information in the issue as filed, the triage reviewer applies the ``status:Needs Info`` label and leaves ``status:Needs Triage`` in place. -If an issue has remained in ``status:Needs Info`` for more than 14 days -without any follow-up communication, the reviewer should apply +If an issue has remained in ``status:Needs Info`` for more than 14 days +without any follow-up communication, the reviewer should apply ``status:Blocked``. A blocked issue should be closed after another 14 days pass without a reply that unblocks it. Our expectation is that every new issue should be examined within a week of its creation. +Triagers should label easier/lower complexity issues as ``good first issue`` to +facilitate beginner contributions. A good first issue should have: + +* A clear, easily understood description with screen shots and expectations that do not require much familiarity with the project +* Links, either in the description or in comments, to documentation and source code files that are relevant to the issue +* Recommended points of contact, either by GitHub username or on other forums (Discourse, etc) where a contributor can get help + +Unless an issue is time-sensitive, such as if it is a release blocker +for an imminent release, experienced Jupyter contributors should avoid +picking up recent issues with the ``good first issue`` label. + Tagging Issues with Labels ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -182,14 +273,25 @@ the label ``foo`` and ``bar baz`` to an issue, comment Contributing from within the browser ------------------------------------ -Using the https://github.com web interface - documented -`here `__ - you -can create and propose a change purely within your browser. -Using `Binder `__, you can test the current master branch and your +Contributing to JupyterLab codebase is also possible without setting up +a local environment, directly from the Web browser: + +- `Gitpod `__ integration is enabled, + however it is not actively maintained, +- GitHub's + `built-in editor `__ + is suitable for contributing very small fixes, +- more advanced `github.dev `__ + editor can be accessed by pressing the dot (``.``) key while in the JupyterLab GitHub repository, +- `jupyterlab-playground `__, + allows to prototype JupyterLab extensions from within JupyterLab and + can be run without installation in the browser using Binder. + +Using `Binder `__, you can test the current main branch and your changes within the browser as well. We recommend you have at least 8 GB of RAM for this. -To build and launch an instance of the latest JupyterLab master, open -`this link `__ +To build and launch an instance of the latest JupyterLab main, open +`this link `__ in a new tab. The build takes about 7 minutes to complete. To test your own branch hosted on GitHub, enter it on https://mybinder.org. @@ -199,32 +301,23 @@ about 7 minutes again. Setting up a local development environment ------------------------------------------ This section explains how to set up a local development environment. We assume you use GNU/Linux, -Mac OS X, or Windows Subsystem for Linux. +macOS, or Windows Subsystem for Linux. If using Windows, we recommend installing `Anaconda for windows `__ and then using the Anaconda command prompt for all installation steps. Installing Node.js and jlpm ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Building JupyterLab from its GitHub source code requires Node.js. The -development version requires Node.js version 12+, as defined in the +development version requires Node.js version 18+, as defined in the ``engines`` specification in -`dev_mode/package.json `__. +`dev_mode/package.json `__. -If you use ``conda``, you can get it with: +If you use `conda `__, you can get it with: .. code:: bash conda install -c conda-forge nodejs -The canvas node package is not properly packaged for Mac OS X with ARM architectures (M1 and M2). -To build JupyterLab on such platforms, you need a few additional packages, and to specify the pkg-config -path: - -.. code:: bash - - conda install -c conda-forge pkg-config pango libpng cairo jpeg giflib librsvg glib - export PKG_CONFIG_PATH=$CONDA_PREFIX/lib/pkgconfig - -If you use `Homebrew `__ on Mac OS X: +If you use `Homebrew `__ on macOS: .. code:: bash @@ -239,6 +332,36 @@ To check which version of Node.js is installed: node -v +.. _Installing Node.js and jlpm section: + +The canvas node package is not properly packaged for macOS with ARM architectures (M1 and M2). +To build JupyterLab on such platforms, you need a few additional packages: + +With conda: + +.. code:: bash + + conda install -c conda-forge pkg-config pango libpng cairo jpeg giflib librsvg glib pixman + export PKG_CONFIG_PATH=$CONDA_PREFIX/lib/pkgconfig + +With Homebrew: + +.. code:: bash + + brew install pkg-config cairo pango libpng jpeg giflib librsvg + +Using automation to set up a local development environment +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +While there is a lot to learn by following the steps above, they can be automated to save time. This section shows how +to do that using Vagrant as an example. + +The main advantages of using automation are: reduced time to get the environment up-and-running, reduced time to +re-build the environment, better standardisation ("baseline", reproducible environments). + +A practical example can be found `there `_ and +includes a ``Vagrantfile``, the bootstrap files and additional documentation. + Installing JupyterLab --------------------- @@ -251,7 +374,7 @@ Then use the following steps: git clone https://github.com//jupyterlab.git cd jupyterlab - pip install -e . + pip install -e ".[dev,test]" jlpm install jlpm run build # Build the dev mode assets (optional) @@ -277,13 +400,10 @@ Notes: Python 3.0+ version of ``pip`` or ``pip3 install -e .`` command to install JupyterLab from the forked repository. - If you see an error that says ``Call to 'pkg-config pixman-1 --libs' - returned exit status 127 while in binding.gyp`` while running the + returned exit status 127 while in binding.gyp`` while running the ``pip install`` command above, you may be missing packages required - by ``canvas``. On macOS with Homebrew, you can add these packages by - running - ``brew install pkg-config cairo pango libpng jpeg giflib librsvg``. - If you are using mamba or conda, you can install the necessary packages - with `conda install -c conda-forge pkg-config glib pango pixman`. + by ``canvas``. Please see `Installing Node.js and jlpm section`_ + of this guide for instructions on how to install these packages. - The ``jlpm`` command is a JupyterLab-provided, locked version of the `yarn `__ package manager. If you have ``yarn`` installed already, you can use the ``yarn`` command when @@ -365,7 +485,21 @@ appropriate package folder: cd packages/notebook jlpm run build:test - jlpm test + jlpm test --runInBand + +.. note:: + + ``--runInBand`` option will run all tests serially in the current process. + We advice to use it as some tests are spinning a Jupyter Server that does not + like to be executed in parallel. + +If you see a test run fail with ``Library not loaded: '@rpath/libpixman-1.0.dylib'`` +(or a different library, such as ``libcairo.2.dylib`` for Mac computers with Apple +Silicon chips) while running the +``jlpm test`` command above, you may be missing packages required +by ``canvas``. Please see +`Installing Node.js and jlpm section`_ +of this guide for instructions on how to install these packages. We use ``jest`` for all tests, so standard ``jest`` workflows apply. Tests can be debugged in either VSCode or Chrome. It can help to add an @@ -422,244 +556,82 @@ must be delayed on minor or major versions. Performance Testing ------------------- -If you are making a change that might affect how long it takes to load -JupyterLab in the browser, we recommend doing some performance testing -using `Lighthouse `__. It -let's you easily compute a number of metrics, like page load time, for -the site. +Benchmark of JupyterLab is done using Playwright. The actions measured are: -To use it, first build JupyterLab in dev mode: +- Opening a file +- Switching from the file to a simple text file +- Switching back to the file +- Closing the file -.. code:: bash +Two files are tested: a notebook with many code cells and another with many markdown cells. - jlpm run build:dev +The test is run on the CI by comparing the result in the commit at which a PR branch started and the PR branch head on +the same CI job to ensure using the same hardware. +The benchmark job is triggered on: -Then, start JupyterLab using the dev build: +- Approved PR review +- PR review that contains the sentence ``please run benchmark`` -.. code:: bash - - jupyter lab --dev-mode --NotebookApp.token='' --no-browser - -Now run Lighthouse against this local server and show the results: +The tests are located in the subfolder ``galata/test/benchmark``. And they can be +executed with the following command: .. code:: bash - jlpm run lighthouse --view + jlpm run test:benchmark -.. image:: ../images/lighthouse.png -Using throttling -^^^^^^^^^^^^^^^^ +A special report will be generated in the folder ``benchmark-results`` that will contain 4 files: -Lighthouse recommends using the system level -`comcast `__ tool to throttle -your network connection and emulate different scenarios. To use it, -first install that tool using ``go``: - -.. code:: bash - - go get github.com/tylertreat/comcast - -Then, before you run Lighthouse, enable the throttling (this requires -sudo): - -.. code:: bash +- ``lab-benchmark.json``: The execution time of the tests and some metadata. +- ``lab-benchmark.md``: A report in Markdown +- ``lab-benchmark.png``: A comparison of execution time distribution +- ``lab-benchmark.vl.json``: The `Vega-Lite `__ description used to produce the PNG file. - run lighthouse:throttling:start +The reference, tagged *expected*, is stored in ``lab-benchmark-expected.json``. It can be +created using the ``-u`` option of Playwright; i.e. ``jlpm run test:benchmark -u``. -This enables the "WIFI (good)" preset of comcast, which should emulate -loading JupyterLab over a local network. +Benchmark parameters +^^^^^^^^^^^^^^^^^^^^ -Then run the lighthouse tests: +The benchmark can be customized using the following environment variables: -.. code:: bash - - jlpm run lighthouse [...] - -Then disable the throttling after you are done: - -.. code:: bash - - jlpm run lighthouse:throttling:stop - -Comparing results -^^^^^^^^^^^^^^^^^ - -Performance results are usually only useful in comparison to other -results. For that reason, we have included a comparison script that can -take two lighthouse results and show the changes between them. - -Let's say we want to compare the results of the production build of -JupyterLab with the normal build. The production build minifies all the -JavaScript, so should load a bit faster. - -First, we build JupyterLab normally, start it up, profile it and save -the results: - -.. code:: bash +- ``BENCHMARK_NUMBER_SAMPLES``: Number of samples to compute the execution time distribution; default 20. +- ``BENCHMARK_OUTPUTFILE``: Benchmark result output file; default ``benchmark.json``. It is overridden in the ``playwright-benchmark.config.js``. +- ``BENCHMARK_REFERENCE``: Reference name of the data; default is ``actual`` for current data and ``expected`` for the reference. - jlpm build:dev - jupyter lab --dev --NotebookApp.token='' --no-browser - - # in new window - jlpm run lighthouse --output json --output-path normal.json - -Then rebuild with the production build and retest: - -.. code:: bash - - jlpm run build:dev:prod - jupyter lab --dev --NotebookApp.token='' --no-browser - - # in new window - jlpm run lighthouse --output json --output-path prod.json - -Now we can use compare the two outputs: - -.. code:: bash - - jlpm run lighthouse:compare normal.json prod.json - -This gives us a report of the relative differences between the audits in -the two reports: - -.. admonition:: Resulting Output - - ``normal.json`` -> ``prod.json`` - - | **First Contentful Paint** - | - -62% Δ - | - 1.9 s -> 0.7 s - | - First Contentful Paint marks the time at which the first text or - image is painted. `Learn - more `__. - - | **First Meaningful Paint** - | - -50% Δ - | - 2.5 s -> 1.3 s - | - First Meaningful Paint measures when the primary content of a - page is visible. `Learn - more `__. - - | **Speed Index** - | - -48% Δ - | - 2.6 s -> 1.3 s - | - Speed Index shows how quickly the contents of a page are visibly - populated. `Learn - more `__. - - | **Estimated Input Latency** - | - 0% Δ - | - 20 ms -> 20 ms - | - Estimated Input Latency is an estimate of how long your app takes - to respond to user input, in milliseconds, during the busiest 5s - window of page load. If your latency is higher than 50 ms, users - may perceive your app as laggy. `Learn - more `__. - - | **Max Potential First Input Delay** - | - 9% Δ - | - 200 ms -> 210 ms - | - The maximum potential First Input Delay that your users could - experience is the duration, in milliseconds, of the longest task. - `Learn - more `__. - - | **First CPU Idle** - | - -50% Δ - | - 2.5 s -> 1.3 s - | - First CPU Idle marks the first time at which the page's main - thread is quiet enough to handle input. `Learn - more `__. - - | **Time to Interactive** - | - -52% Δ - | - 2.5 s -> 1.2 s - | - Time to interactive is the amount of time it takes for the page - to become fully interactive. `Learn - more `__. - - | **Avoid multiple page redirects** - | - -2% Δ - | - Potential savings of 10 ms -> Potential savings of 10 ms - | - Redirects introduce additional delays before the page can be - loaded. `Learn - more `__. - - | **Minimize main-thread work** - | - -54% Δ - | - 2.1 s -> 1.0 s - | - Consider reducing the time spent parsing, compiling and executing - JS. You may find delivering smaller JS payloads helps with this. - - | **JavaScript execution time** - | - -49% Δ - | - 1.1 s -> 0.6 s - | - Consider reducing the time spent parsing, compiling, and - executing JS. You may find delivering smaller JS payloads helps - with this. `Learn - more `__. - - | **Preload key requests** - | - -100% Δ - | - Potential savings of 240 ms -> - | - Consider using to prioritize fetching - resources that are currently requested later in page load. `Learn - more `__. - - | **Uses efficient cache policy on static assets** - | - 0% Δ - | - 1 resource found -> 1 resource found - | - A long cache lifetime can speed up repeat visits to your page. - `Learn - more `__. - - | **Avoid enormous network payloads** - | - -86% Δ - | - Total size was 30,131 KB -> Total size was 4,294 KB - | - Large network payloads cost users real money and are highly - correlated with long load times. `Learn - more `__. - - | **Minify JavaScript** - | - -100% Δ - | - Potential savings of 23,041 KB -> - | - Minifying JavaScript files can reduce payload sizes and script - parse time. `Learn - more `__. - - | **Enable text compression** - | - -86% Δ - | - Potential savings of 23,088 KB -> Potential savings of 3,112 KB - | - Text-based resources should be served with compression (gzip, - deflate or brotli) to minimize total network bytes. `Learn - more `__. - - | **Avoid an excessive DOM size** - | - 0% Δ - | - 1,268 elements -> 1,268 elements - | - Browser engineers recommend pages contain fewer than ~1,500 DOM - elements. The sweet spot is a tree depth < 32 elements and fewer - than 60 children/parent element. A large DOM can increase memory - usage, cause longer `style - calculations `__, - and produce costly `layout - reflows `__. - `Learn - more `__. +More tests can be carried out manually on JupyterLab branches and run weekly on the default branch in +`jupyterlab/benchmarks `__ repository. Visual Regression and UI Tests ------------------------------ -As part of JupyterLab CI workflows, UI tests are run with visual regression checks. `Galata `__ is used for UI testing. Galata provides a high level API to control and inspect JupyterLab UI programmatically, testing tools and CLI to manage tests and other tasks. - -UI tests are run for each commit into JupyterLab project in PRs or direct commits. Code changes can sometimes cause UI tests to fail for various reasons. After each test run, Galata generates a user friendly test result report which can be used to inspect failing UI tests. Result report shows the failure reason, call-stack up to the failure and detailed information on visual regression issues. For visual regression errors, reference image and test capture image, along with diff image generated during comparison are provided in the report. You can use these information to debug failing tests. Galata test report can be downloaded from GitHub Actions page for a UI test run. Test artifact is named ``ui-test-output`` and once you extract it, you can access the report by opening ``test/report/index.html`` in a browser window. +As part of JupyterLab CI workflows, UI tests are run with visual regression checks. +`Galata `__ is used for UI +testing. Galata provides `Playwright `__ helpers to control and +inspect JupyterLab UI programmatically. + +UI tests are run for each commit into JupyterLab project in PRs or direct commits. Code +changes can sometimes cause UI tests to fail for various reasons. After each test run, +Galata generates a user friendly test result report which can be used to inspect failing +UI tests. Result report shows the failure reason, call-stack up to the failure and +detailed information on visual regression issues. For visual regression errors, reference +image and test capture image, along with diff image generated during comparison are +provided in the report. You can use these information to debug failing tests. Galata test +report can be downloaded from GitHub Actions page for a UI test run. Test artifact is +named ``galata-report`` and once you extract it, you can access the report by launching +a server to serve the files ``python -m http.server -d ``. +Then open *http://localhost:8000* with your web browser. Main reasons for UI test failures are: 1. **A visual regression caused by code changes**: - Sometimes unintentional UI changes are introduced by modifications to project source code. Goal of visual regression testing is to detect this kind of UI changes. If your PR / commit is causing visual regression, then debug and fix the regression caused. You can locally run and debug the UI tests to fix the visual regression. Follow the instructions in steps 5-7 of ``Adding a new UI test suite guide`` in `UI Testing documentation `__ to locally debug and fix UI tests. Once you have a fix, you can push the change to your GitHub branch and test with GitHub actions. + Sometimes unintentional UI changes are introduced by modifications to project source + code. Goal of visual regression testing is to detect this kind of UI changes. If your + PR / commit is causing visual regression, then debug and fix the regression caused. + You can locally run and debug the UI tests to fix the visual regression. To debug your + test, you may run ``PWDEBUG=1 jlpm playwright test ``. Once you + have a fix, you can push the change to your GitHub branch and test with GitHub actions. 2. **An intended update to user interface**: @@ -669,16 +641,23 @@ Main reasons for UI test failures are: - ``please update galata snapshots``: A bot will push a new commit to your PR updating galata test snaphsots. + - ``please update documentation snapshots``: A bot will push a new commit to your PR updating + documentation test snapshots. - ``please update snapshots``: Combine the two previous comments effects. -For more information on UI Testing, please read the `UI Testing developer documentation `__ and `Galata documentation `__. + The bot will react with +1 emoji to indicate that the run started and then comment + back once it concluded. + +For more information on UI Testing, please read the `UI Testing developer documentation `__ +and `Playwright documentation `__. Good Practices for Integration tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Here are some good practices to follow when writing integration tests: -- Don't compare multiple screenshots in the same test; if the first comparison breaks, it will require running multiple times the CI workflow to fix all tests. +- Don't compare multiple screenshots in the same test; if the first comparison breaks, + it will require running multiple times the CI workflow to fix all tests. Contributing to the debugger front-end -------------------------------------- @@ -850,15 +829,11 @@ Writing Documentation Documentation is written in Markdown and reStructuredText. In particular, the documentation on our Read the Docs page is written in reStructuredText. To ensure that the Read the Docs page builds, you'll -need to install the documentation dependencies with ``conda``: +need to install the documentation dependencies with ``pip``: .. code:: bash - conda env create -f docs/environment.yml - -.. code:: bash - - conda activate jupyterlab_documentation + pip install -e ".[docs]" To test the docs run: @@ -883,17 +858,17 @@ Or with ``jlpm``: Writing Style ^^^^^^^^^^^^^ -- The documentation should be written in the second person, referring - to the reader as "you" and not using the first person plural "we." +- Write documentation in the second person, referring + to the reader as "you". Do not use the first person plural "we." The author of the documentation is not sitting next to the user, so using "we" can lead to frustration when things don't work as expected. - Avoid words that trivialize using JupyterLab such as "simply" or "just." Tasks that developers find simple or easy may not be for users. -- Write in the active tense, so "drag the notebook cells..." rather - than "notebook cells can be dragged..." -- The beginning of each section should begin with a short (1-2 +- Write in the active tense. For example, "drag the notebook cellsâ€Ļ" rather + than "notebook cells can be draggedâ€Ļ". +- The beginning of each section should begin with a short (1–2 sentence) high-level description of the topic, feature or component. - Use "enable" rather than "allow" to indicate what JupyterLab makes possible for users. Using "allow" connotes that we are giving them @@ -905,36 +880,56 @@ User Interface Naming Conventions Documents, Files, and Activities """""""""""""""""""""""""""""""" -Files are referred to as either files or documents, depending on the -context. +Refer to files as either files or documents, depending on the context. -Documents are more human centered. If human viewing, interpretation, -interaction is an important part of the experience, it is a document in -that context. For example, notebooks and markdown files will often be -referring to as documents unless referring to the file-ness aspect of it +*Documents* are more human centered. If human viewing, interpretation, +or interaction is an important part of the experience, use the term +"document". For example, notebooks and Markdown files will often be +referred to as documents except in the context of a file system (e.g., the notebook filename). -Files are used in a less human-focused context. For example, we refer to -files in relation to a file system or file name. +Use the term *files* in a less human-focused context. For example, +refer to files in relation to a file system or file name. + +*Activities* are either an opened document or another UI panel that is +not related to a file, such as terminals, consoles or the inspector. + +Notebook Cells +"""""""""""""" + +A notebook contains *cells*, each of which have *input* and one or more +*outputs*. When the user runs a cell, the kernel reads and executes the +input and generates outputs. The notebook then displays the cell's output. +The term *output* describes one of possibly multiple results of running a +cell. *Cell output* describes the collective output of one cell. Use +*outputs of all cells* to describe all outputs from all cells. -Activities can be either a document or another UI panel that is not file -backed, such as terminals, consoles or the inspector. An open document -or file is an activity in that it is represented by a panel that you can -interact with. +Command Names +""""""""""""" + +Command names appear in menus, in the Command Palette, and in toolbar buttons +(where the name typically appears on hover). + +- Keep command names short, concise, and unambiguous. +- Add an ellipsis (â€Ļ) after any command name that requires more options. This + tells the user that they should expect a pop-up window to appear before they + execute the command. +- Commands should use verbs in the imperative case. Do not use articles with nouns. + For example, write "Clear Cell", not "Clear the Cell" or "Clearing Cell". Element Names """"""""""""" -- The generic content area of a tabbed UI is a panel, but prefer to - refer to the more specific name, such as “File browser.” Tab bars - have tabs which toggle panels. -- The menu bar contains menu items, which have their own submenus. -- The main work area can be referred to as the work area when the name +- The generic content area of a tabbed UI is a *panel*. Refer to a panel + by its most specific name, such as “File browser.” *Tab bars* + have *tabs* that let a user view different panels. +- The *menu bar* contains *menu items* that have their own *submenus*. +- Refer to the *main work area* as the work area when the name is unambiguous. -- When describing elements in the UI, colloquial names are preferred - (e.g., “File browser” instead of “Files panel”). +- When describing elements in the UI, prefer colloquial names over + technical names. For example, use “File browser” instead of “Files panel”. -The majority of names are written in lower case. These names include: +Write most element names in lowercase. These names include: - tab - panel @@ -950,19 +945,16 @@ The majority of names are written in lower case. These names include: - cell inspector - code console -The following sections of the user interface should be in title case, -directly quoting a word in the UI: +Write the following sections of the user interface with one or more +initial capitals, mirroring their use in the UI: +- Activity Bar - File menu - Files tab - Running panel - Tabs panel - Simple Interface mode -The capitalized words match the label of the UI element the user is -clicking on because there does not exist a good colloquial name for the -tool, such as “file browser” or “command palette”. - See :ref:`interface` for descriptions of elements in the UI. The Jupyter Server Extension @@ -1034,16 +1026,12 @@ them out against your copy of JupyterLab, you can easily do so using the ``link`` command: 1. Make your changes and then build the external package -2. Register a link to the modified external package - - - navigate to the external package dir and run ``jlpm link`` - -3. Link JupyterLab to modded package +2. Link JupyterLab to modded package - navigate to top level of your JupyterLab repo, then run - ``jlpm link ""`` + ``jlpm link --all`` -You can then (re)build JupyterLab (eg ``jlpm run build``) and your +3. You can then (re)build JupyterLab (eg ``jlpm run build``) and your changes should be picked up by the build. To restore JupyterLab to its original state, you use the ``unlink`` @@ -1052,13 +1040,13 @@ command: 1. Unlink JupyterLab and modded package - navigate to top level of your JupyterLab repo, then run - ``jlpm unlink ""`` + ``jlpm unlink --all`` 2. Reinstall original version of the external package in JupyterLab - run ``jlpm install --check-files`` -You can then (re)build JupyterLab and everything should be back to +3. You can then (re)build JupyterLab and everything should be back to default. Possible Linking Pitfalls @@ -1098,6 +1086,9 @@ preparing them: - Make sure the screenshot does not contain copyrighted material (preferable), or the license is allowed in our documentation and clearly stated. +- For screenshots, you should prefer creating visual tests. This allows + to update them dynamically. Those tests are defined in ``galata/test/documentation`` + folder. - If taking a png screenshot, use the Firefox or Chrome developer tools to do the following: diff --git a/docs/source/developer/css.rst b/docs/source/developer/css.rst index ec7178a88e2a..89d2cb4fac47 100644 --- a/docs/source/developer/css.rst +++ b/docs/source/developer/css.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. _css: CSS Patterns @@ -70,7 +73,7 @@ CSS variable usage ^^^^^^^^^^^^^^^^^^ JupyterLab includes a default set of CSS variables in the file -`packages/theme-light-extension/style/variables.css `_. +`packages/theme-light-extension/style/variables.css `_. To ensure consistent design in JupyterLab, all built-in and third party extensions should use these variables in their styles if at all diff --git a/docs/source/developer/internationalization.rst b/docs/source/developer/internationalization.rst index a3bc0642864f..c82d7fe80b77 100644 --- a/docs/source/developer/internationalization.rst +++ b/docs/source/developer/internationalization.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + Internationalization and Localization ===================================== @@ -9,18 +12,18 @@ Four elements are used to handle the internationalization of JupyterLab: - `language-packs `_ repository: It contains the source strings, their translations, the language packs and the GitHub workflows to update and publish the translations. -- `Crowdin project `_: Crowdin is the cloud-based solution +- `Crowdin project `_: Crowdin is the cloud-based solution that streamlines localization management for JupyterLab. This is the place where contributors can translate JupyterLab strings. - `jupyterlab-translate `_ repository: Python library defining helpers to deal with internationalization (e.g. extracting the strings). -- `Cookiecutter template `_ repository: It +- `Package template `_ repository: It defines the Python package template of a language pack. The *language-packs* repository is the main entry point. It interacts with Crowdin to publish newer source strings and get the latest translation. It also creates and updates the language packs. -And finally it publishes them. All those actions are carried out using helpers defined in -``jupyterlab-translate`` and the cookiecutter template. +And finally it publishes them. All those actions are carried out using helpers defined in +``jupyterlab-translate`` and the package template. Workflows --------- @@ -89,6 +92,8 @@ The workflow is as follow: requests updating the source strings need to be closed in order for the Crowdin integration to re-open the PR. +.. _language-update: + Language packs update ^^^^^^^^^^^^^^^^^^^^^ @@ -97,21 +102,21 @@ This is done by manually triggering the `Prepare language packs for release `_ should pass on that pull request 4. A maintainer needs to merge the pull request .. note:: - The version policy for the language packs is to follow major and minor version numbers of + The version policy for the language packs is to follow major and minor version numbers of JupyterLab and bumping the post number for any intermediate updates. The version of all language packs is identical to ease maintenance. @@ -121,7 +126,7 @@ The workflow is: Language packs publication ^^^^^^^^^^^^^^^^^^^^^^^^^^ -Each time a ``.bumpversion.cfg`` in any *language packs* is modified the `Create Release and publish packages `_ +Each time package version is modified the `Create Release and publish packages `_ will be automatically triggered. Its steps are: 1. Check that all language packs have identical versions @@ -136,3 +141,17 @@ will be automatically triggered. Its steps are: Publication is done using jupyterlab-bot credentials on all PyPI projects. `Conda recipe `_ should be updated by the auto-tick bot of conda-forge. + + +Adding a new language pack +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This requires the following manual actions to be executed (in that order): + +1. Add the language on Crowdin +2. Execute the :ref:`language-update` workflow +3. Manually upload the package on PyPI +4. Update the owner on PyPI to add jupyterlab-bot as maintainer +5. Acknowledge the grant for the bot +6. Update the `github action list `_ +7. Update the `conda-forge variant list `_ diff --git a/docs/source/developer/patterns.rst b/docs/source/developer/patterns.rst index d01edfeb5061..8965eeb7b9ed 100644 --- a/docs/source/developer/patterns.rst +++ b/docs/source/developer/patterns.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + Design Patterns =============== diff --git a/docs/source/developer/performance.rst b/docs/source/developer/performance.rst new file mode 100644 index 000000000000..9476418b1382 --- /dev/null +++ b/docs/source/developer/performance.rst @@ -0,0 +1,96 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + +Performance tricks +================== + +Windowed list +------------- + +A list windowing algorithm is implemented in a dedicated widget ``WindowedList`` provided by ``@jupyterlab/ui-components``. + +This widget will have a DOM structure like this: + +.. code::html + + + +The reason for encapsulating the visible items in such tree comes from the need to position the +current view correctly in a fake document that has the real height. + +Notebook documents +------------------ + +Performance analysis of notebook documents in JupyterLab point out to two main bottlenecks: +editors style computation and rendered markdown with lots of math expressions. The best +technique to alleviate those problems are to attach to the DOM only the cells in the viewport. +However code cell outputs bring a huge constraint that their internal state is within the +DOM node (e.g. the zoom level on a map view). So the outputs cannot be detached once displayed +With those considerations in mind, here is the algorithm coded for the notebook windowing. + +.. note:: + + When initializing the view, the code cell outputs are scanned to detect if they contain + ``text/html`` output defining ``style`` and/or ``scripts`` elements. If they do, those + cells are rendered to ensure styles and JavaScript are applied as they may leak outside + their definition cell (e.g. injection of custom styles). + +When cell widgets are instantiated, their children are not created (i.e. the editor, the +outputs,â€Ļ) and they are not attached to the DOM. The view is updated on scroll events following: + +1. Get the scroll position in the notebook +2. Get the cells range to be displayed +3. Attach the cells in viewport to the notebook + a. Before attaching the cell, if it was never attached, instantiate its children. + b. For code cells previously attach, change its visibility and attach all children except the output area. + c. Add the cell widget to a resize observer that trigger and viewport update +4. Detach cells that left the viewport + a. Remove cell widget from resize observer. + b. For code cells, the output area is not detached but hidden. All other children are detached. + +Due to the code cells being kept in the DOM, we need to update the data attribute +``data-windowed-list-index`` when the cells list changes. This is required to attach at the +correct position the cell when the viewport changes. + +The list windowing algorithm is coded in a dedicated widget ``WindowedList``. The notebook +extends it and uses a specialized layout to deal with code cells, ``NotebookWindowedLayout``. +The code cell layout is also customized ``CodeCellLayout`` to keep the output area attached +but not the other children. + +.. warning:: + + The current implementation does not handle *iframe* well. In Chrome, the iframe states are + reset every time they leave and renter the viewport. In Firefox, it does not happen when + scrolling comes from mouse scrolls. But the reset happens when jumping to a specific position + that was out of viewport; e.g. searching for a word or navigating to a heading. + +Side effect of the implementation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- It is still possible to search cell outputs DOM nodes. But when turning on that option, + the UI may freeze as all outputs never rendered will need to be rendered. +- The cell editor is available only for cell that have been at least once in the viewport. + The editor is not destroyed when the cells are out of the viewport. So its state can be modified. +- HTML element measurements cannot capture margins. Therefore the cell containers should not use it. + Padding is the solution as measurements is limited to border sizing. This is because top and bottom + margins between adjacent elements `can be collapsed `__ + by the web browsers. + +Viewport state +^^^^^^^^^^^^^^ + +Each cell widget implements those three attributes: + +- ``isPlaceholder`` will be false if the cell has never been attached (and therefore have no children instantiated). +- ``ready`` returns a promise that resolves when a cell is fully instantiated. After that the editor and any children will exist. +- ``inViewport`` whether the cell is currently in viewport or not. You can listen to the signal inViewportChanged. + +The notebook widget has the following helper : + +- ``scrollToItem`` to scroll to a specific cell index. Like for scrolling an element into view, various mode are available. diff --git a/docs/source/developer/repo.rst b/docs/source/developer/repo.rst index 564cb3e7216e..d97d4b700a86 100644 --- a/docs/source/developer/repo.rst +++ b/docs/source/developer/repo.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. _developer-guide: General Codebase Orientation @@ -10,7 +13,7 @@ In particular, there are many TypeScript packages and a single Python package. The Python package contains server-side code, and also distributes the bundled-and-compiled TypeScript code. -See the `Contributing Guidelines `__ +See the `Contributing Guidelines `__ for detailed developer installation instructions. Directories @@ -22,7 +25,7 @@ are described here. Python package: ``jupyterlab/`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This, along with the ``setup.py``, comprises the Python code for the project. +This, along with the ``pyproject.toml``, comprises the Python code for the project. This includes the notebook server extension, JupyterLab's command line interface, entrypoints, and Python tests. @@ -58,7 +61,7 @@ The ``lab-dev`` endpoint is the equivalent of checking out the repo locally and The ``lab-spliced`` endpoint is the equivalent of building JupyterLab in spliced mode and running ``jupyter lab``. See the `Development workflow for source extensions <../extension/extension_dev.html#development-workflow-for-source-extensions>`__ for more information on spliced mode. -Build utilities: ``builtutils/`` +Build utilities: ``buildutils/`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ An ``npm`` package that contains several utility scripts for managing @@ -83,7 +86,7 @@ Documentation: ``docs/`` ^^^^^^^^^^^^^^^^^^^^^^^^ This directory contains the Sphinx project for this documentation. -You can create an environment to build the documentation using ``conda create -f environment.yml``, +You can install the dependencies for building the documentation using ``pip install .[docs]``, and you can build the documentation by running ``make html``. The entry point to the built docs will then be in ``docs/build/index.html``. diff --git a/docs/source/extension/documents.rst b/docs/source/extension/documents.rst index 43eaa4b3679e..26dde156fb1e 100644 --- a/docs/source/extension/documents.rst +++ b/docs/source/extension/documents.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. _documents: Documents @@ -19,10 +22,10 @@ Overview of document architecture --------------------------------- A 'document' in JupyterLab is represented by a model instance implementing the -`IModel <../api/interfaces/docregistry.documentregistry.imodel.html>`__ interface. +`IModel <../api/interfaces/docregistry.DocumentRegistry.IModel.html>`__ interface. The model interface is intentionally fairly small, and concentrates on representing the data in the document and signaling changes to that data. Each model has an -associated `context <../api/interfaces/docregistry.documentregistry.icontext.html>`__ +associated `context <../api/interfaces/docregistry.DocumentRegistry.IContext.html>`__ instance as well. The context for a model is the bridge between the internal data of the document, stored in the model, and the file metadata and operations possible on the file, such as save and revert. Since many objects will need both the context @@ -33,41 +36,27 @@ representing the file. For example, a notebook can be opened with a notebook mod and with a text model. Different models for the same file path do not directly communicate with each other. -Models contain an instance of `ModelDB <../api/classes/observables.modeldb-1.html>`__ -that acts as data storage for the model's content. In JupyterLab 3.1, we introduced -the package ``@jupyterlab/shared-models`` to swap ``ModelDB`` as a data storage -to make 'documents' collaborative. We implemented these shared models using -`Yjs `_, a high-performance CRDT for building collaborative applications -that automatically sync. -Starting with JupyterLab 3.6, the shared models have been extracted in the external package +Models contain an instance of `ISharedDocument `_ +that acts as data storage for the model's content. As of JupyterLab 4, the default data +storage implementation is a `YDocument `_ +based on `Yjs `_, a high-performance CRDT for building collaborative +applications. Both the interface and the implementation are provided by the package `@jupyter/ydoc `_. -At the moment, models contain both a ``ModelDB`` and a ``Shared Model`` instance, so it is -possible to access ``ModelDB`` yet. But starting with JupyterLab 4, the ``ModelDB`` storage will be removed. -`Document widgets <../api/classes/docregistry.documentregistry-1.html>`__ represent +`Document widgets <../api/classes/docregistry.DocumentWidget-1.html>`__ represent a view of a document model. There can be multiple document widgets associated with a single document model, and they naturally stay in sync with each other since they are views on the same underlying data model. -`Shared Models `__ are models -using Yjs’ shared types as a data structures instead of ``ModelDB``. - -The `Document Registry <../api/classes/docregistry.documentregistry-1.html>`__ +The `Document Registry <../api/classes/docregistry.DocumentRegistry-1.html>`__ is where document types and factories are registered. Plugins can require a document registry instance and register their content types and providers. -The `Document Manager <../api/classes/docmanager.documentmanager-1.html>`__ +The `Document Manager <../api/classes/docmanager.DocumentManager-1.html>`__ uses the Document Registry to create models and widgets for documents. The Document Manager handles the lifecycle of documents for the application. -The `Document Provider <../api/classes/docprovider.websocketproviderwithlocks-1.html>`__ -is a WebSocket provider that syncs documents through a new end-point (``api/yjs``) -in the JupyterLab server. `Providers `_ -abstract Yjs from the network technology your application uses. They sync Yjs -documents through a communication protocol or a database. Most providers have -in common that they use the concept of room names to connect Yjs documents. - Document Registry ----------------- @@ -79,8 +68,13 @@ Document Registry - widget factories for specific model factories - widget extension factories -`Widget Factories <../api/classes/docregistry.documentregistry-1.html#addwidgetfactory>`__ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. note:: + + We recommend you to look at the `document example `__ + to help understanding a pratical case. + +`Widget Factories <../api/classes/docregistry.DocumentRegistry-1.html#addWidgetFactory>`__ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Create a widget for a given file. @@ -88,16 +82,16 @@ Create a widget for a given file. - The notebook widget factory that creates NotebookPanel widgets. -`Model Factories <../api/classes/docregistry.documentregistry-1.html#addmodelfactory>`__ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +`Model Factories <../api/classes/docregistry.DocumentRegistry-1.html#addModelFactory>`__ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Create a model for a given file. Models are generally differentiated by the contents options used to fetch the model (e.g. text, base64, notebook). -`Widget Extension Factories <../api/classes/docregistry.documentregistry-1.html#addwidgetextension>`__ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +`Widget Extension Factories <../api/classes/docregistry.DocumentRegistry-1.html#addWidgetExtension>`__ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Adds additional functionality to a widget type. An extension instance is created for each widget instance, enabling the extension to add @@ -108,11 +102,13 @@ functionality to each widget or observe the widget and/or its context. - The ipywidgets extension that is created for NotebookPanel widgets. - Adding a button to the toolbar of each NotebookPanel widget. -`File Types <../api/classes/docregistry.documentregistry-1.html#addfiletype>`__ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +`File Types <../api/classes/docregistry.DocumentRegistry-1.html#addFileType>`__ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Adds a new file type to be understood through a mimetype and file extensions within JupyterLab. -`Document Models <../api/interfaces/docregistry.documentregistry.imodel.html>`__ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +`Document Models <../api/interfaces/docregistry.DocumentRegistry.IModel.html>`__ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Created by the model factories and passed to widget factories and widget extension factories. Models are the way in which we interact with the @@ -120,8 +116,8 @@ data of a document. For a simple text file, we typically only use the ``to/fromString()`` methods. A more complex document like a Notebook contains more points of interaction like the Notebook metadata. -`Document Contexts <../api/interfaces/docregistry.documentregistry.icontext.html>`__ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +`Document Contexts <../api/interfaces/docregistry.DocumentRegistry.IContext.html>`__ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Created by the Document Manager and passed to widget factories and widget extensions. The context contains the model as one of its diff --git a/docs/source/extension/extension_dev.rst b/docs/source/extension/extension_dev.rst index 013cef67ed86..901a878aea14 100644 --- a/docs/source/extension/extension_dev.rst +++ b/docs/source/extension/extension_dev.rst @@ -1,12 +1,39 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. _developer_extensions: -Extension Developer Guide -========================= +Develop Extensions +================== The JupyterLab application is comprised of a core application object and a set of extensions. JupyterLab extensions provide nearly every function in JupyterLab, including notebooks, document editors and viewers, code consoles, terminals, themes, the file browser, contextual help system, debugger, and settings editor. Extensions even provide more fundamental parts of the application, such as the menu system, status bar, and the underlying communication mechanism with the server. A JupyterLab extension is a package that contains a number of JupyterLab plugins. We will discuss how to write a plugin, then how to package together a set of plugins into a JupyterLab extension. +See the sections below for more detailed information, or browse the rest of this page for an overview. + +.. warning:: + Your extensions may break with new releases of JupyterLab. As noted in :ref:`versioning_notes`, + JupyterLab development and release cycles follow semantic versioning, so we recommend planning + your development process to account for possible future breaking changes that may disrupt users + of your extensions. Consider documenting your maintenance plans to users in your project, or + setting an upper bound on the version of JupyterLab your extension is compatible with in your + project's package metadata. + +.. toctree:: + :maxdepth: 1 + + extension_points + ui_components + documents + notebook + virtualdom + ui_helpers + internationalization + identity + extension_tutorial + extension_migration + Other resources --------------- @@ -22,14 +49,13 @@ We provide a set of guides to get started writing extensions for JupyterLab: - :ref:`developer-extension-points`: A list of the most common JupyterLab extension points. - Another common pattern for extending JupyterLab document widgets with application plugins is covered in :ref:`documents`. -Cookiecutters -^^^^^^^^^^^^^ +Extension template +^^^^^^^^^^^^^^^^^^ -We provide several cookiecutters to create JupyterLab extensions: +We provide several templates to create JupyterLab extensions: -- `extension-cookiecutter-ts `_: Create a JupyterLab extension in TypeScript -- `extension-cookiecutter-js `_: Create a JupyterLab extension in JavaScript -- `mimerender-cookiecutter-ts `_: Create a MIME Renderer JupyterLab extension in TypeScript +- `extension-template `_: Create a JupyterLab extension using `copier `_ +- [DEPRECATED] `extension-cookiecutter-ts `_: Create a JupyterLab extension using `cookiecutter `_ (use the copier template instead). API Reference Documentation ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,22 +63,22 @@ API Reference Documentation Here is some autogenerated API documentation for JupyterLab and Lumino packages: - `JupyterLab API Documentation <../api/>`_ -- `Lumino API Documentation `_ - +- `Lumino API Documentation `_ Overview of Extensions ---------------------- A JupyterLab plugin is the basic unit of extensibility in JupyterLab. An extension is a package that contains one or more JupyterLab plugins. Extensions can be distributed in two ways: -- A *source extension* is a JavaScript (npm) package that exports one or more plugins. Installing a source extension requires a user to rebuild JupyterLab. This rebuilding step requires Node.js and may take a lot of time and memory, so some users may not be able to install a source extension. However, the total size of the JupyterLab code delivered to a user's browser may be reduced compared to using prebuilt extensions. See :ref:`deduplication` for the technical reasons for rebuilding JupyterLab when a source extension is installed. -- A *prebuilt extension* (new in JupyterLab 3.0) distributes a bundle of JavaScript code prebuilt from a source extension that can be loaded into JupyterLab without rebuilding JupyterLab. In this case, the extension developer uses tools provided by JupyterLab to compile a source extension into a JavaScript bundle that includes the non-JupyterLab JavaScript dependencies, then distributes the resulting bundle in, for example, a Python pip or conda package. Installing a prebuilt extensions does not require Node.js. +- A *prebuilt extension* (since JupyterLab 3.0) distributes a bundle of JavaScript code prebuilt from a source extension that can be loaded into JupyterLab without rebuilding JupyterLab. In this case, the extension developer uses tools provided by JupyterLab to compile a source extension into a JavaScript bundle that includes the non-JupyterLab JavaScript dependencies, then distributes the resulting bundle in, for example, a Python pip or conda package. Installing a prebuilt extensions does not require Node.js. +- [DEPRECATED] A *source extension* is a JavaScript (npm) package that exports one or more plugins. Installing a source extension requires a user to rebuild JupyterLab. This rebuilding step requires Node.js and may take a lot of time and memory, so some users may not be able to install a source extension. However, the total size of the JupyterLab code delivered to a user's browser may be reduced compared to using prebuilt extensions. See :ref:`deduplication` for the technical reasons for rebuilding JupyterLab when a source extension is installed. An extension can be published both as a source extension on NPM and as a prebuilt extension (e.g., published as a Python package). In some cases, system administrators may even choose to install a prebuilt extension by directly copying the prebuilt bundle to an appropriate directory, circumventing the need to create a Python package. If a source extension and a prebuilt extension with the same name are installed in JupyterLab, the prebuilt extension takes precedence. -Because prebuilt extensions do not require a JupyterLab rebuild, they have a distinct advantage in multiuser systems where JupyterLab is installed at the system level. On such systems, only the system administrator has permissions to rebuild JupyterLab and install source extensions. Since prebuilt extensions can be installed at the per-user level, the per-environment level, or the system level, each user can have their own separate set of prebuilt extensions that are loaded dynamically in their browser on top of the system-wide JupyterLab. +Because prebuilt extensions do not require a JupyterLab rebuild, they have a distinct advantage in multi-user systems where JupyterLab is installed at the system level. On such systems, only the system administrator has permissions to rebuild JupyterLab and install source extensions. Since prebuilt extensions can be installed at the per-user level, the per-environment level, or the system level, each user can have their own separate set of prebuilt extensions that are loaded dynamically in their browser on top of the system-wide JupyterLab. .. tip:: + We recommend publishing prebuilt extensions in Python packages for user convenience. Plugins @@ -74,6 +100,7 @@ An application plugin is a JavaScript object with a number of metadata fields. A const plugin: JupyterFrontEndPlugin = { id: 'my-extension:plugin', + description: 'Provides a new service.', autoStart: true, requires: [ILabShell, ITranslator], optional: [ICommandPalette], @@ -84,6 +111,7 @@ An application plugin is a JavaScript object with a number of metadata fields. A The ``id`` and ``activate`` fields are required and the other fields may be omitted. For more information about how to use the ``requires``, ``optional``, or ``provides`` fields, see :ref:`services`. - ``id`` is a required unique string. The convention is to use the NPM extension package name, a colon, then a string identifying the plugin inside the extension. +- ``description`` is an optional string. It allows to document the purpose of a plugin. - ``autostart`` indicates whether your plugin should be activated at application startup. Typically this should be ``true``. If it is ``false`` or omitted, your plugin will be activated when any other plugin requests the token your plugin is providing. - ``requires`` and ``optional`` are lists of :ref:`tokens ` corresponding to services other plugins provide. These services will be given as arguments to the ``activate`` function when the plugin is activated. If a ``requires`` service is not registered with JupyterLab, an error will be thrown and the plugin will not be activated. - ``provides`` is the :ref:`token ` associated with the service your plugin is providing to the system. If your plugin does not provide a service to the system, omit this field and do not return a value from your ``activate`` function. @@ -147,18 +175,18 @@ A pattern in core JupyterLab is to create and export a token from a third packag .. _rendermime: -Mime Renderer Plugins +MIME Renderer Plugins ^^^^^^^^^^^^^^^^^^^^^ -Mime Renderer plugins are a convenience for creating a plugin -that can render mime data in a notebook and files of the given mime type. Mime renderer plugins are more declarative and more restricted than standard plugins. +MIME Renderer plugins are a convenience for creating a plugin +that can render mime data in a notebook and files of the given mime type. MIME renderer plugins are more declarative and more restricted than standard plugins. A mime renderer plugin is an object with the fields listed in the -`rendermime-interfaces IExtension <../api/interfaces/rendermime_interfaces.irendermime.iextension.html>`__ +`rendermime-interfaces IExtension <../api/interfaces/rendermime_interfaces.IRenderMime.IExtension.html>`__ object. -JupyterLab has a `pdf mime renderer extension `__, for example. In core JupyterLab, this is used to view pdf files and view pdf data mime data in a notebook. +JupyterLab has a `pdf mime renderer extension `__, for example. In core JupyterLab, this is used to view pdf files and view pdf data mime data in a notebook. -We have a `mime renderer tutorial `__ walking through creating a mime renderer extension which adds mp4 video rendering to JupyterLab. We also have a `cookiecutter for mime renderer extensions `__ in TypeScript. +We have a `MIME renderer example `__ walking through creating a mime renderer extension which adds mp4 video rendering to JupyterLab. The `extension template `_ supports MIME renderer extensions. The mime renderer can update its data by calling ``.setData()`` on the model it is given to render. This can be used for example to add a @@ -171,13 +199,13 @@ document can then be saved by the user in the usual manner. Theme plugins ^^^^^^^^^^^^^ -A theme is a special application plugin that registers a theme with the ``ThemeManager`` service. Theme CSS assets are specially bundled in an extension (see :ref:`themePath`) so they can be unloaded or loaded as the theme is activated. Since CSS files referenced by the ``style`` or ``styleModule`` keys are automatically bundled and loaded on the page, the theme files should not be referenced by these keys. +A theme is a special application plugin that registers a theme with the ``ThemeManager`` service. Theme CSS assets are specially bundled in an extension (see :ref:`themePath`) so they can be unloaded or loaded as the theme is activated. Since CSS files referenced by the ``style`` or ``styleModule`` keys are automatically bundled and loaded on the page, the theme files should not be referenced by these keys. The extension package containing the theme plugin must include all static assets that are referenced by ``@import`` in its theme CSS files. Local URLs can be used to reference files relative to the location of the referring sibling CSS files. For example ``url('images/foo.png')`` or ``url('../foo/bar.css')`` can be used to refer local files in the theme. Absolute URLs (starting with a ``/``) or external URLs (e.g. ``https:``) can be used to refer to external assets. -See the `JupyterLab Light Theme `__ for an example. +See the `JupyterLab Light Theme `__ for an example. -See the `TypeScript theme cookiecutter `__ for a quick start to developing a theme plugin. +See the `TypeScript extension template `__ (choosing ``theme`` as ``kind`` ) for a quick start to developing a theme plugin. .. _source_extensions: @@ -186,13 +214,7 @@ Source Extensions A source extension is a JavaScript (npm) package that exports one or more plugins. All JupyterLab extensions are developed as source extensions (for example, prebuilt extensions are built from source extensions). -A source extension has metadata in the ``jupyterlab`` field of its ``package.json`` file. The `JSON schema `__ for the metadata is distributed in the ``@jupyterlab/builder`` package. - -If you would like publish your source extension to npm and want users to be able to install your source extension, we recommend including the npm keyword ``jupyterlab-extension`` in ``package.json``. This enables JupyterLab's extension manager to find your extension and display it for users in its graphical interface:: - - "keywords": [ - "jupyterlab-extension" - ], +A source extension has metadata in the ``jupyterlab`` field of its ``package.json`` file. The `JSON schema `__ for the metadata is distributed in the ``@jupyterlab/builder`` package. We will talk about each ``jupyterlab`` metadata field in ``package.json`` for source extensions below. @@ -219,7 +241,7 @@ The ``jupyterlab.extension`` field signifies that the package exports one or mor .. _mimeExtension: -Mime Renderer Plugins +MIME Renderer Plugins ^^^^^^^^^^^^^^^^^^^^^ The ``jupyterlab.mimeExtension`` field signifies that the package exports mime renderer plugins. Like the ``jupyterlab.extension`` field, the value can be a boolean (indicating a mime renderer plugin or list of mime renderer plugins is the default export from the ``main`` field), or a string, which is the relative path to the module exporting (as the default export) one or more mime renderer plugins. @@ -257,14 +279,16 @@ For example, the JupyterLab ``filebrowser-extension`` package exports the ``@jup "schemaDir": "schema", } -The file browser setting schema file (which specifies some default keyboard shortcuts and other settings for the filebrowser) is located in ``schema/browser.json`` (see `here `__). +The file browser setting schema file (which specifies some default keyboard shortcuts and other settings for the filebrowser) is located in ``schema/browser.json`` (see `here `__). See the -`fileeditor-extension `__ +`fileeditor-extension `__ for another example of an extension that uses settings. Please ensure that the schema files are included in the ``files`` metadata in ``package.json``. +When declaring dependencies on JupyterLab packages, use the ``^`` operator before a package version so that the build system installs the newest patch or minor version for a given major version. For example, ``^4.0.0`` will install version 4.0.0, 4.0.1, 4.1.0, etc. + A system administrator or user can override default values provided in a plugin's settings schema file with the :ref:`overrides.json ` file. .. _disabledExtensions: @@ -503,7 +527,7 @@ Custom webpack configuration can be used to enable webpack features, configure a } }; -This custom config will be merged with the `prebuilt extension config `_ +This custom config will be merged with the `prebuilt extension config `_ when building the prebuilt extension. .. _prebuilt_dev_workflow: @@ -537,14 +561,14 @@ If you are using TypeScript, the TypeScript compiler would complain because the When adding the path to find JupyterLab dependencies, it may cause troubles with other dependencies (like lumino or react) in your project because JupyterLab packages will take its dependencies from JupyterLab ``node_modules`` folder. In contrast, your packages will take them from your ``node_modules`` folder. To solve this problem, you’ll need to add the dependencies with conflicts to ``resolutions`` in your ``package.json``. This way, both projects (JupyterLab and your extension) use the same version of the duplicated dependencies. -We provide a `cookiecutter `_ that handles all of the scaffolding for an extension author, including the shipping of appropriate data files, so that when the user installs the package, the prebuilt extension ends up in ``share/jupyter/labextensions`` +We provide a `extension template `_ that handles all of the scaffolding for an extension author, including the shipping of appropriate data files, so that when the user installs the package, the prebuilt extension ends up in ``share/jupyter/labextensions`` .. _distributing_prebuilt_extensions: Distributing a prebuilt extension ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Prebuilt extensions can be distributed by any system that can copy the prebuilt assets into an appropriate location where JupyterLab can find them. The `official extension cookiecutter `_ shows how to distribute prebuilt extensions via Python pip or conda packages. A system package manager, or even just an administrative script that copies directories, could be used as well. +Prebuilt extensions can be distributed by any system that can copy the prebuilt assets into an appropriate location where JupyterLab can find them. The `official extension template `_ shows how to distribute prebuilt extensions via Python pip or conda packages. A system package manager, or even just an administrative script that copies directories, could be used as well. To distribute a prebuilt extension, copy its :ref:`output directory ` to a location where JupyterLab will find it, typically ``/share/jupyter/labextensions/``, where ```` is the JavaScript package name in the ``package.json``. For example, if your JavaScript package name is ``@my-org/my-package``, then the appropriate directory would be ``/share/jupyter/labextensions/@my-org/my-package``. @@ -569,7 +593,58 @@ This ``install.json`` file is used by JupyterLab to help a user know how to mana * ``packageName``: This is the package name of the prebuilt extension in the package manager above, which may be different than the package name in ``package.json``. * ``uninstallInstructions``: This is a short block of text giving the user instructions for uninstalling the prebuilt extension. For example, it might instruct them to use a system package manager or talk to a system administrator. +.. _dev_trove_classifiers: + +PyPI Trove Classifiers +"""""""""""""""""""""" + +Extensions distributed as Python packages may declare additional metadata in the form of +`trove classifiers `__. These improve the browsing +experience for users on `PyPI `__. While including the license, +development status, Python versions supported, and other topic classifiers are useful +for many audiences, the following classifiers are specific to Jupyter and JupyterLab. + +.. code-block:: + + Framework :: Jupyter + Framework :: Jupyter :: JupyterLab + Framework :: Jupyter :: JupyterLab :: 1 + Framework :: Jupyter :: JupyterLab :: 2 + Framework :: Jupyter :: JupyterLab :: 3 + Framework :: Jupyter :: JupyterLab :: 4 + Framework :: Jupyter :: JupyterLab :: Extensions + Framework :: Jupyter :: JupyterLab :: Extensions :: Mime Renderers + Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt + Framework :: Jupyter :: JupyterLab :: Extensions :: Themes + +Include each relevant classifier (and its parents) to help describe what your package +provides to prospective users in your ``setup.py``, ``setup.cfg``, or ``pyproject.toml``. +In particular ``Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt`` is used by +the extension manager to get the available extensions from PyPI.org. + +.. hint:: + + For example, a theme, only compatible with JupyterLab 3, and distributed as + a ready-to-run, prebuilt extension might look like: + + .. code-block:: python + + # setup.py + setup( + # the rest of the package's metadata + # ... + classifiers=[ + "Framework :: Jupyter", + "Framework :: Jupyter :: JupyterLab", + "Framework :: Jupyter :: JupyterLab :: 3", + "Framework :: Jupyter :: JupyterLab :: Extensions", + "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt", + "Framework :: Jupyter :: JupyterLab :: Extensions :: Themes", + ] + ) + This would be discoverable from, for example, a + `PyPI search for theme extensions `__. .. _source_dev_workflow: @@ -582,8 +657,8 @@ While authoring a source extension, you can use the command: .. code-block:: bash - npm install # install npm package dependencies - npm run build # optional build step if using TypeScript, babel, etc. + jlpm install # install npm package dependencies + jlpm run build # optional build step if using TypeScript, babel, etc. jupyter labextension install # install the current directory as an extension This causes the builder to re-install the source folder before building @@ -597,7 +672,7 @@ included in ``jupyter labextension list``. When using local extensions and linked packages, you can run the command -:: +.. code-block:: shell jupyter lab --watch @@ -607,11 +682,14 @@ the CSS files) are watched by the WebPack process. This means that if your extension is in TypeScript you'll have to run a ``jlpm run build`` before the changes will be reflected in JupyterLab. To avoid this step you can also watch the TypeScript sources in your extension which is -usually assigned to the ``tsc -w`` shortcut. If WebPack doesn't seem to +usually assigned to the ``tsc -w`` shortcut. If webpack doesn't seem to detect the changes, this can be related to `the number of available watches `__. Note that the application is built against **released** versions of the -core JupyterLab extensions. If your extension depends on JupyterLab +core JupyterLab extensions. You should specify the version using the ``^`` +operator, such as ``^4.0.0``, so that the build system can use newer minor and patch +versions of a package with a particular major version. +If your extension depends on JupyterLab packages, it should be compatible with the dependencies in the ``jupyterlab/static/package.json`` file. Note that building will always use the latest JavaScript packages that meet the dependency requirements of JupyterLab itself and any installed extensions. If you wish to test against a specific patch release of one of the core JupyterLab packages you can @@ -620,7 +698,7 @@ dependencies. If you want to test a source extension against the unreleased versions of JupyterLab, you can run the command -:: +.. code-block:: shell jupyter lab --watch --splice-source @@ -650,24 +728,6 @@ not enabled in our build configuration. To build a compatible package set ``output.libraryTarget`` to ``"commonjs2"`` in your Webpack configuration. (see `this `__ example repo). -Another option to try out your extension with a local version of JupyterLab is to add it to the -list of locally installed packages and to have JupyterLab register your extension when it starts up. - -You can do this by adding your extension to the ``jupyterlab.externalExtensions`` key -in the ``dev_mode/package.json`` file. It should be a mapping -of extension name to version, just like in ``dependencies``. Then run ``jlpm run integrity`` -and these extensions should be added automatically to the ``dependencies`` and pulled in. - -When you then run ``jlpm run build && jupyter lab --dev`` or ``jupyter lab --dev --watch`` this extension -will be loaded by default. For example, this is how you can add the Jupyter Widgets -extensions: - -:: - - "externalExtensions": { - "@jupyter-widgets/jupyterlab-manager": "2.0.0" - }, - If you publish your extension on ``npm.org``, users will be able to install it as simply ``jupyter labextension install ``, where ```` is the name of the published ``npm`` package. You can alternatively provide a @@ -683,15 +743,16 @@ We encourage extension authors to add the `jupyterlab-extension GitHub topic .. _testing_with_jest: Testing your extension -^^^^^^^^^^^^^^^^^^^^^^ +---------------------- + +.. note:: + + We highly recommend using the `extension template `_ to set up tests configuration. There are a number of helper functions in ``testutils`` in this repo (which is a public ``npm`` package called ``@jupyterlab/testutils``) that can be used when writing tests for an extension. See ``tests/test-application`` for an example -of the infrastructure needed to run tests. There is a ``karma`` config file -that points to the parent directory's ``karma`` config, and a test runner, -``run-test.py`` that starts a Jupyter server. - +of the infrastructure needed to run tests. If you are using `jest `__ to test your extension, you will need to transpile the jupyterlab packages to ``commonjs`` as they are using ES6 modules @@ -699,48 +760,39 @@ that ``node`` does not support. To transpile jupyterlab packages, you need to install the following package: -:: +.. code-block:: shell jlpm add --dev jest @types/jest ts-jest @babel/core@^7 @babel/preset-env@^7 -Then in `jest.config.js`, you will specify to use babel for js files and ignore +Then in ``jest.config.js``, you will specify to use babel for js files and ignore all node modules except the ES6 modules: -:: - - const esModules = [ - '@jupyterlab/', - 'lib0', - 'y\\-protocols', - 'y\\-websocket', - 'yjs' - ].join('|'); - - module.exports = { - preset: 'ts-jest/presets/js-with-babel', - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], - transformIgnorePatterns: [`/node_modules/(?!${esModules}).+`], - globals: { - 'ts-jest': { - tsConfig: 'tsconfig.json' - } - }, - ... // Other options useful for your extension - }; +.. code-block:: javascript + + const jestJupyterLab = require('@jupyterlab/testutils/lib/jest-config'); + + const esModules = ['@jupyterlab/'].join('|'); + + const baseConfig = jestJupyterLab(__dirname); + + module.exports = { + ...baseConfig, + automock: false, + collectCoverageFrom: [ + 'src/**/*.{ts,tsx}', + '!src/**/*.d.ts', + '!src/**/.ipynb_checkpoints/*' + ], + coverageReporters: ['lcov', 'text'], + testRegex: 'src/.*/.*.spec.ts[x]?$', + transformIgnorePatterns: [ + ...baseConfig.transformIgnorePatterns, + `/node_modules/(?!${esModules}).+` + ] + }; Finally, you will need to configure babel with a ``babel.config.js`` file containing: -:: - - module.exports = { - presets: [ - [ - '@babel/preset-env', - { - targets: { - node: 'current' - } - } - ] - ] - }; +.. code-block:: javascript + + module.exports = require('@jupyterlab/testutils/lib/babel.config'); diff --git a/docs/source/extension/extension_migration.rst b/docs/source/extension/extension_migration.rst index 5ba5a8c444f3..d5bcf5fafe66 100644 --- a/docs/source/extension/extension_migration.rst +++ b/docs/source/extension/extension_migration.rst @@ -1,7 +1,457 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. _extension_migration: Extension Migration Guide -========================= +================================================ + +JupyterLab 3.x to 4.x +--------------------- + +Because of significant type changes from JupyterLab 3.x to 4.x, we recommend **publishing a new major version** +of your extension to work with each major version of JupyterLab. For examples of extensions that use different +major versions for Lab 3 and Lab 4, see `jupyterlab-vim `_ +and `jupyter-ai `_. + +Upgrading extension using the upgrade script +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +JupyterLab 4.x provides a script to upgrade an existing extension to use the new extension system and packaging. + +.. note:: + + Back up your extension - the best if you use a version control like git, is to work on a new branch. + +First, make sure to update to JupyterLab 4 and install ``copier`` and some dependencies. With ``pip``: + +.. code:: bash + + pip install -U jupyterlab + pip install "copier~=8.0" jinja2-time tomli-w + + +Or with ``conda``: + +.. code:: bash + + conda install -c conda-forge jupyterlab=4 "copier=8" jinja2-time tomli-w + + +Then at the root folder of the extension, run: + +.. code:: bash + + python -m jupyterlab.upgrade_extension . + +The upgrade script creates the necessary files for packaging the JupyterLab extension as a Python package. +The script will ask you for all files if you want to override them or not. By default the configuration files +will be overridden for the newer version. In particular, if you were using Python setuptools (aka ``setup.py`` +and/or ``setup.cfg``), you will like need to update the ``pyproject.toml`` file (see +`PEP example `_). + +The upgrade script also updates the dependencies in ``package.json`` to the ``^4.0.0`` packages. + +For more details about the new file structure and packaging of the extension, check out the extension tutorial: :ref:`extension_tutorial` + +.. note:: + + You will need to modify the code of your extension if it is impacted by the API changes mentioned below. + +jlpm +^^^^ + +The utility ``jlpm`` uses Yarn 3 (previously Yarn 1). This will require updating your +package configuration. + +- Create a file ``.yarnrc.yml`` containing: + +.. code-block:: yaml + + enableImmutableInstalls: false + nodeLinker: node-modules + +- Add to ``.gitignore`` + +.. code-block:: + + .yarn/ + +- Run ``jlpm install`` + This will reset your ``yarn.lock`` content as its format has changed. + +.. note:: + + You can find more information on upgrading Yarn from version 1 to version 3 in + [Yarn documentation](https://v3.yarnpkg.com/getting-started/migration). + +If you are hit by multiple versions of the same packages (like ``@lumino/widgets``), +TypeScript may complain that the types are not matching. One possible solution +is to force packages deduplication using: + +.. code-block:: sh + + jlpm dlx yarn-berry-deduplicate + +API breaking changes +^^^^^^^^^^^^^^^^^^^^ + +.. note:: + + With JupyterLab 4.x, the npm package version policy changed to not bump major version with + the Python package unless required to ease extension compatibility. + +Here is a list of JupyterLab npm packages that encountered API changes and therefore have +bumped their major version (following semver convention). We want to point out particularly +``@jupyterlab/documentsearch`` and ``@jupyterlab/toc`` API that have been fully reworked. + +- ``@jupyterlab/application`` from 3.x to 4.x + * Major version bump to allow alternate ``ServiceManager`` implementations in ``JupyterFrontEnd``. + Specifically this allows the use of a mock manager. + This also makes the ``JupyterLab.IOptions`` more permissive to not require a shell when options are + given and allow a shell that meets the ``ILabShell`` interface. + As a consequence, all other ``@jupyterlab/`` packages have their major version bumped too. + See https://github.com/jupyterlab/jupyterlab/pull/11537 for more details. + * Rename token ``@jupyterlab/apputils:IConnectionLost`` to ``@jupyterlab/application:IConnectionLost``. +- ``@jupyterlab/apputils`` from 3.x to 4.x + * Rename ``IToolbarWidgetRegistry.registerFactory`` to ``IToolbarWidgetRegistry.addFactory`` + * ``ISanitizer`` and ``ISanitizer.IOptions`` are deprecated in favor of ``IRenderMime.ISanitizer`` and + ``IRenderMime.ISanitizerOptions`` in ``@jupyterlab/rendermime-interfaces``. + * Global ``sessionContextDialogs`` is removed; you should request the token ``ISessionContextDialogs`` (from ``@jupyterlab/apputils``). +- ``@jupyterlab/attachments`` from 3.x to 4.x + Removed ``modelDB`` from ``IAttachmentsModel.IOptions``. +- ``@jupyterlab/buildutils`` from 3.x to 4.x + * The ``create-theme`` script has been removed. If you want to create a new theme extension, you + should use the `TypeScript extension template `_ + (choosing ``theme`` as ``kind`` ) instead. + * The ``add-sibling`` script has been removed. Check out :ref:`source_dev_workflow` instead. + * The ``exitOnUuncaughtException`` util function has been renamed to ``exitOnUncaughtException`` (typo fix). +- ``@jupyterlab/cells`` from 3.x to 4.x + * ``MarkdownCell.toggleCollapsedSignal`` renamed ``MarkdownCell.headingCollapsedChanged`` + To support notebook windowing, cell widget children (e.g. the editor or the output area) are not instantiated + when the cell is attached to the notebook. You can test for ``isPlaceholder()`` to see if the cell has been + fully instantiated or wait for the promise ``ready`` to be resolved. Additionally an attribute ``inViewport`` + and a signal ``inViewportChanged`` are available to test if the cell is attached to the DOM. + If you instantiate standalone cells outside of a notebook, you will probably need to set the constructor option + ``placeholder`` to ``false`` to ensure direct rendering of the cell. + * ``InputArea.defaultContentFactory`` and ``Cell.defaultContentFactory`` have been removed. If you need it, you + can request the token ``IEditorServices`` from ``@jupyterlab/codeeditor``. Then you can use + ``new Cell.ContentFactory({ editorFactory: token.factoryService.newInlineEditor });``. +- ``@jupyterlab/celltags`` from 3.x to 4.0 + The ``@jupyterlab/celltags`` package has been removed and replaced by a widget in ``@jupyterlab/celltags-extension``. + This widget is now rendered using ``@jupyterlab/metadataform``. +- ``@jupyterlab/codeeditor`` from 3.x to 4.0 + * ``CodeEditor.IEditor`` has changed: + - ``resizeToFit()`` is removed + - ``addKeydownHandler()`` is removed - you should add a CodeMirror extension ``EditorView.domEventHandlers`` with + ``Prec.high`` (to ensure it is not captured by keyboard shortcuts). + - ``injectExtension()`` added as experimental to inject a CodeMirror extension - you should prefer registering + new extensions with ``IEditorExtensionRegistry``. + * ``CodeEditor.IOptions`` has two new optional attributes: + - ``extensions?: Extensions[]`` to provide custom extensions at editor instantiation + - ``inline?: boolean`` whether the editor is a subpart of a document (like the notebook) or not. + * ``CodeEditorWrapper.IOptions`` has changed to ``{ factory, model, editorOptions }``. + * ``CodeViewerWidget.IOptions`` has changed to ``{ factory, model, editorOptions }``. +- ``@jupyterlab/codemirror`` from 3.x to 4.0 + * Configuration parameters changes: + - ``fontFamily``, ``fontSize`` and ``lineHeight``: grouped in a subdictionnary ``customStyles``. + - ``insertSpaces``: changed for ``indentUnit`` that can take a value within ['Tab', '1', '2', '4', '8'] + - ``lineWrap``: changed - it is now a boolean. + - ``showTrailingSpace``: renamed ``highlightTrailingWhitespace`` + - ``coverGutterNextToScrollbar``: removed + - ``electricChars``: removed + - ``extraKeys``: removed - you should register new keymap using the CodeMirror extension ``keymap.of(KeyBinding[])`` + - ``handlePaste``: removed + - ``keymap``: removed + - ``lineSeparator``: removed - Line separator are normalized to ``\n`` + - ``lineWiseCopyCut``: removed - this is the default behavior + - ``scrollbarStyle``: removed + - ``styleSelectedText``: removed + - ``selectionPointer``: removed + - ``wordWrapColumn``: removed + * ``Mode`` has been removed. You can instead request the token ``IEditorLanguageHandler``. That provides + similar API: + - ``Mode.registerModeInfo`` -> ``IEditorLanguageHandler.addLanguage`` + - ``Mode.ensure()`` -> ``IEditorLanguageHandler.getLanguage()`` + - ``Mode.modeList`` -> ``IEditorLanguageHandler.getLanguages()`` + - ``Mode.run()`` -> ``IEditorLanguageHandler.highlight()`` + - ``Mode.findBest()`` -> ``IEditorLanguageHandler.findBest()`` + - ``Mode.findByName()`` -> ``IEditorLanguageHandler.findByName()`` + - ``Mode.findByMIME()`` -> ``IEditorLanguageHandler.findByMIME()`` + - ``Mode.findByExtension()`` -> ``IEditorLanguageHandler.findByExtension()`` + * ``EditorSyntaxStatus`` moved to ``@jupyterlab/fileeditor`` +- ``@jupyterlab/codemirror-extension`` from 3.x to 4.0 + * Moved commands: + - ``codemirror:change-theme`` -> ``fileeditor:change-theme`` (moved to ``@juptyerlab/fileeditor-extension``) + - ``codemirror:change-mode`` -> ``fileeditor:change-language`` (moved to ``@juptyerlab/fileeditor-extension``) + - ``codemirror:find`` -> ``fileeditor:find`` (moved to ``@juptyerlab/fileeditor-extension``) + - ``codemirror:go-to-line`` -> ``fileeditor:go-to-line`` (moved to ``@juptyerlab/fileeditor-extension``) + * Removed command: ``codemirror:change-keymap`` + * Moved plugins: + - ``@jupyterlab/codemirror-extension:commands`` integrated within ``@jupyterlab/fileeditor-extension:plugin`` + - ``@jupyterlab/codemirror-extension:editor-syntax-status`` -> ``@jupyterlab/fileeditor-extension:editor-syntax-status`` + - ``@jupyterlab/codemirror-extension:editor-syntax-status`` -> ``@jupyterlab/fileeditor-extension:editor-syntax-status`` +- ``@jupyterlab/completer`` from 3.x to 4.x + Major version was bumped following major refactor aimed at performance improvements and enabling easier third-party integration. + + * Adding custom completion suggestions (items): + - In 3.x and earlier adding custom completion items required re-registering the completer connector for each file/cell + using ``register`` method of old manager provided by ``ICompletionManager`` token; in 4.x this token and associated + ``ICompletableAttributes`` interface was removed and a proper method of registering a custom source of completions + (a provider of completions) was added. To create a completer provider for JupyterLab, users need to implement the + ``ICompletionProvider`` interface and then register this provider with ``ICompletionProviderManager`` token. + - In 3.x merging completions from different sources had to be performed by creating a connector internally merging + results from other connectors. in 4.x ``IProviderReconciliator`` is used to merge completions from multiple providers, + and can be customised in constructor for custom completion handlers (``CompletionHandler``); customizing reconciliator + in JupyterLab-managed completers is not yet possible. + * Rendering with ``Completer.IRenderer``: + - In 3.x it was not possible to easily swap the renderer of JupyterLab-managed completers. + In 4.x the renderer from the completion provider with highest rank is now used for all + JupyterLab-managed completers. This behaviour is subject to revision in the future (please leave feedback). + - Completer box is now using delayed rendering for off-screen content to improve time to first paint + for top suggestions. To position the completer without rendering all items we search for the widest + item using heuristic which can be adjusted in custom renderers (``itemWidthHeuristic``). + - The documentation panel now implements a loading indicator (a progress bar) customizable via + optional ``createLoadingDocsIndicator`` renderer method. + - ``createItemNode`` was removed in favour of ``createCompletionItemNode`` which is now required. + - ``createCompletionItemNode`` is no longer responsible for sanitization of labels which is now a + responsibility of the model (see below). + * Model: + - In 3.x it was not possible to easily swap the model of JupyterLab-managed completers. + In 4.x the model factory from the completion provider with highest rank is now used for + JupyterLab-managed completers. This behaviour is subject to revision in the future (please leave feedback). + - Old methods for updating and accessing the completion items: ``setOptions``, ``options``, and ``items`` were removed + in favour of ``completionItems`` and ``setCompletionItems`` which are now required members of ``Completer.IModel``. + - New signal ``queryChanged`` was added and has to be emitted by models. + - Model is now responsible for sanitization of labels and preserving original label on ``insertText`` attribute + (if not already defined); this change was required to properly handle escaping of HTML tags. +- ``@jupyterlab/codeeditor`` from 3.x to 4.x + * Remove ``ISelectionStyle`` (and therefore ``defaultSelectionStyle`` and ``IEditor.selectionStyle``). This was envisaged + for real-time collaboration. But this is not used in the final implementation. +- ``@jupyterlab/console`` from 3.x to 4.x + The type of ``IConsoleHistory.sessionContext`` has been updated to ``ISessionContext | null`` instead of ``ISessionContext``. + This might break the compilation of plugins accessing the ``sessionContext`` from a ``ConsoleHistory``, + in particular those with the strict null checks enabled. +- ``@jupyterlab/coreutils`` from 3.x to 4.x + The ``Time`` namespace does not use the ``moment`` library anymore for managing dates. Instead it switched to using + the ``Intl`` API now available in modern web browsers. The ``Time.format`` function is still available but does not accept the + ``timeFormat`` argument anymore. +- ``@jupyterlab/debugger`` from 3.x to 4.x + * The command ``debugger:pause`` command ID has been renamed ``debugger:pause-on-exceptions`` to avoid ambiguity with + pausing the current running thread. +- ``@jupyterlab/docmanager`` from 3.x to 4.x + * The ``renameDialog`` now receives the ``DocumentRegistry.Context`` instead of a path. + * The interface ``DocumentManager.IWidgetOpener`` is now ``IDocumentWidgetOpener`` and is provided + by a new plugin ``@jupyterlab/docmanager-extension:opener``. + The ``IDocumentWidgetOpener`` interface also now defines an ```opened``` signal that is emitted when a widget is opened. + * Removed the property ``docProviderFactory`` from the interface ``DocumentManager.IOptions``. +- ``@jupyterlab/docregister`` from 3.x to 4.x + * ``TextModelFactory.preferredLanguage(path: string)`` will always return ``''``. The editor languages is not available globally to provided it. + You can recover the feature if needed, by requesting the token ``IEditorLanguageHandler`` from ``@jupyterlab/codemirror``. Then you can use + ``token.findByFileName(widget.context.path)?.name ?? ''``. +- ``@jupyterlab/docprovider`` from 3.x to 4.x + This package is no longer present in JupyterLab. For documentation related to Real-Time Collaboration, please check out + `RTC's documentation `_ +- ``@jupyterlab/docregistry`` from 3.x to 4.x + * Removed the property ``docProviderFactory`` from the interface ``Context.IOptions``. + * The constructor of the class ``DocumentModel`` receives a parameter ``DocumentModel.IOptions``. + * The method ``IModelFactory.createNew`` receives a parameter ``DocumentRegistry.IModelOptions``. + * The method ``TextModelFactory.createNew`` receives a parameter ``DocumentModel.IOptions``. +- ``@jupyterlab/documentsearch`` from 3.x to 4.x + * ``@jupyterlab/documentsearch:plugin`` has been renamed to ``@jupyterlab/documentsearch-extension:plugin`` + * ``@jupyterlab/documentsearch:labShellWidgetListener`` has been renamed to ``@jupyterlab/documentsearch-extension:labShellWidgetListener`` + + This may impact application configuration (for instance if the plugin was disabled). + The search provider API has been fully reworked. But the logic is similar, for new type of documents + you will need to register a ``ISearchProviderFactory`` to the ``ISearchProviderRegistry``. The + factory will build a ``ISearchProvider`` for the document widget. +- ``@jupyterlab/extensionmanager`` from 3.x to 4.x + The frontend API has been drastically reduced to fetch all information from the backend. It is now advised + that you implement a custom ``ExtensionManager`` class for your needs rather than overriding the frontend plugins. + See ``jupyterlab/extensions/pypi.py`` for an example using PyPI.org and pip. You can then register your manager + by defining an entry point in the Python package; see ``pyproject.toml::project.entry-points."jupyterlab.extension_manager_v1"``. +- ``@jupyterlab/fileeditor`` from 3.x to 4.x + Remove the class ``FileEditorCodeWrapper``, instead, you can use ``CodeEditorWrapper`` from ``@jupyterlab/codeeditor``. +- ``@jupyterlab/filebrowser`` from 3.x to 4.x + * Remove the property ``defaultBrowser`` from the interface ``IFileBrowserFactory``. The default browser is now provided by it own + plugin by requiring the token ``IDefaultFileBrowser``. + * Remove the ``useFuzzyFilter`` setter from the ``FileBrowser`` class. +- ``@jupyterlab/filebrowser-extension`` from 3.x to 4.x + Remove command ``filebrowser:create-main-launcher``. You can replace by ``launcher:create`` (same behavior) + All launcher creation actions are moved to ``@jupyterlab/launcher-extension``. +- ``@jupyterlab/imageviewer-extension`` from 3.x to 4.x + Removed ``addCommands`` from public API +- ``@jupyterlab/mainmenu`` from 3.x to 4.x + * ``IMainMenu.addMenu`` signature changed from ``addMenu(menu: Menu, options?: IMainMenu.IAddOptions): void`` + to ``addMenu(menu: Menu, update?: boolean, options?: IMainMenu.IAddOptions): void`` + * Removed ``createEditMenu``, ``createFileMenu``, ``createKernelMenu``, ``createViewMenu``, ``createRunMenu``, + ``createTabsMenu``, ``createHelpMenu`` from public API. +- ``@jupyterlab/notebook`` from 3.x to 4.x + * ``NotebookWidgetFactory.IOptions`` has no ``sessionDialogs`` option any more. + * The ``NotebookPanel._onSave`` method is now ``private``. + * ``NotebookActions.collapseAll`` method renamed to ``NotebookActions.collapseAllHeadings``. + * Command ``Collapsible_Headings:Toggle_Collapse`` renamed to ``notebook:toggle-heading-collapse``. + * Command ``Collapsible_Headings:Collapse_All`` renamed to ``notebook:collapse-all-headings``. + * Command ``Collapsible_Headings:Expand_All`` renamed to ``notebook:expand-all-headings``. + * To support windowing, a new method ``scrollToItem(index, behavior)`` is available to scroll to any + cell that may or may not be in the DOM. And new ``cellInViewportChanged`` signal is available to listen + for cells entering or leaving the viewport (in windowing mode). And ``scrollToCell(cell)`` is now returning + a ``Promise`` calling internally ``scrollToItem``. + * ``fullyRendered``, ``placeholderCellRendered`` and ``remainingCellToRenderCount`` have been removed. + The defer rendering mode still exists. It will render some cells during spare CPU Idle time. + * Settings ``numberCellsToRenderDirectly``, ``remainingTimeBeforeRescheduling``, ``renderCellOnIdle``, + ``observedTopMargin`` and ``observedBottomMargin`` have been removed. Instead a ``windowingMode`` + with value of *defer*, *full* or *none* and ``overscanCount`` have been added to manage the rendering + mode. + * Added the property ``sharedModel`` to the interface ``NotebookModel.IOptions``. + * The method ``NotebookModelFactory.createNew`` receives a parameter ``NotebookModelFactory.IModelOptions``. + * The default Notebook toolbar's ``restart-and-run`` button now refers to the command + ``notebook:restart-run-all`` instead of ``runmenu:restart-and-run-all``. + * ``StaticNotebook.defaultContentFactory`` has been removed. If you need it, you can request the token + ``IEditorServices`` from ``@jupyterlab/codeeditor``. You can obtain it by requested + ``new NotebookPanel.ContentFactory({ editorFactory: token.factoryService.newInlineEditor });`` + * ``notebooktools`` module does not provides anymore the ``ActiveCellTool``, the ``NotebookMetadataEditorTool`` + and the ``CellMetadataEditorTool``. All these widget are replaced by widgets in ``@jupyterlab/notebook-extension``, + and are rendered using ``@jupyterlab/metadataform``. + The ``KeySelector`` has also been removed as not used anymore, replaced by the use of ``@jupyterlab/metadataform`` + to provides selection for metadata keys. +- ``@jupyterlab/rendermime`` from 3.x to 4.x + * The markdown parser has been extracted to its own plugin ``@jupyterlab/markedparser-extension:plugin`` + that provides a new token ``IMarkdownParser`` (defined in ``@jupyterlab/rendermime``). + Consequently the ``IRendererFactory.createRenderer`` has a new option ``markdownParser``. + * [Not breaking] ``IRenderMime.IExtension`` has a new optional ``description: string`` attribute for documentation. +- ``@jupyterlab/rendermime-interfaces`` from 3.x to 4.x + Remove ``IRenderMime.IRenderer.translator?`` attribute; the translator object is still passed to + the constructor if needed by the renderer factory. +- ``@jupyterlab/services`` from 6.x to 7.x + * Remove ``Contents.IDrive.modelDBFactory`` and ``Contents.IManager.getModelDBFactory``. + * Added ``Contents.IDrive.sharedModelFactory`` and ``Contents.IManager.getsharedModelFactory``. +- ``@jupyterlab/shared-models`` from 3.x to 4.x + This package is no longer present in JupyterLab. For documentation related to the shared models, + please check out `@jupyter/ydoc documentation `_. +- ``@jupyterlab/statusbar`` from 3.x to 4.x + * Setting ``@jupyterlab/statusbar-extension:plugin . startMode`` moved to ``@jupyterlab/application-extension:shell . startMode`` + * Plugin ``@jupyterlab/statusbar-extension:mode-switch`` renamed to ``@jupyterlab/application-extension:mode-switch`` + * Plugin ``@jupyterlab/statusbar-extension:kernel-status`` renamed to ``@jupyterlab/apputils-extension:kernel-status`` + * Plugin ``@jupyterlab/statusbar-extension:running-sessions-status`` renamed to ``@jupyterlab/apputils-extension:running-sessions-status`` + * Plugin ``@jupyterlab/statusbar-extension:line-col-status`` renamed to ``@jupyterlab/codemirror-extension:line-col-status`` + * ``HoverBox`` component moved from ``@jupyterlab/apputils`` to ``@jupyterlab/ui-components``. + * Removed ``STATUSBAR_PLUGIN_ID`` from public API. +- ``@jupyterlab/terminal`` from 3.x to 4.x + * Xterm.js upgraded from 4.x to 5.x + * ``IThemeObject.selection`` renamed to ``selectionBackground`` +- ``@jupyterlab/terminal-extension`` from 3.x to 4.x + Removed ``addCommands`` from public API +- ``@jupyterlab/toc`` from 3.x to 4.x + ``@jupyterlab/toc:plugin`` renamed ``@jupyterlab/toc-extension:registry`` + This may impact application configuration (for instance if the plugin was disabled). + The namespace ``TableOfContentsRegistry`` has been renamed ``TableOfContents``. + The API has been fully reworked. The new table of content providers must implement a factory + ``TableOfContents.IFactory`` that will create a model ``TableOfContents.IModel`` + for supported widget. The model provides a list of headings described by a ``text`` and + a ``level`` and optionally a ``prefix``, a ``collapsed`` state and a ``dataset`` (data + DOM attributes dictionary). +- ``@jupyterlab/ui-components`` from 3.x to 4.x + * Major version bumped following removal of Blueprint JS dependency. Extensions using proxied + components like ``Checkbox``, ``Select`` or ``Intent`` will need to import them explicitly + from Blueprint JS library. Extensions using ``Button``, ``Collapse`` or ``InputGroup`` may + need to switch to the Blueprint components as the interfaces of those components in JupyterLab + do not match those of Blueprint JS. + * Remove ``Collapse`` React component. + * Form component registry changes: + - Rename the plugin ``'@jupyterlab/ui-components-extension:form-component-registry'`` to ``'@jupyterlab/ui-components-extension:form-renderer-registry'`` + - Rename the ``IFormComponentRegistry`` token to ``IFormRendererRegistry``, from ``@jupyterlab/ui-components:ISettingEditorRegistry`` + to ``@jupyterlab/ui-components:IFormRendererRegistry``. + - The ``FormRendererRegistry`` registers ``IFormRenderer`` instead of ``Field`` renderers. + A ``IFormRenderer`` defines a ``fieldRenderer`` (this is the renderer to set for backward compatibility) + or a ``widgetRenderer``. + The renderer id must follow the convention ``.``. This is to + ensure a custom renderer is not used for property with the same name but different schema. +- ``@jupyterlab/translation`` from 3.x to 4.x + Renamed the method ``locale`` into the property ``languageCode`` in the ``NullTranslator`` +- ``@jupyterlab/vdom`` and ``@jupyterlab/vdom-extension`` have been removed. + The underlying `vdom `_ Python package is unmaintained. + So it was decided to drop it from core packages. +- ``jupyter.extensions.hub-extension`` from 3.x to 4.x + * Renamed ``jupyter.extensions.hub-extension`` to ``@jupyterlab/hub-extension:plugin``. + * Renamed ``jupyter.extensions.hub-extension:plugin`` to ``@jupyterlab/hub-extension:menu``. +- TypeScript 5.0 update + As a result of the update to TypeScript 5.0, a couple of interfaces have had their definitions changed. + The ``anchor`` parameter of ``HoverBox.IOptions`` is now a ``DOMRect`` instead of ``ClientRect``. + The ``CodeEditor.ICoordinate`` interface now extends ``DOMRectReadOnly`` instead of ``JSONObject, ClientRect``. +- React 18.2.0 update + The update to React 18.2.0 (from 17.0.1) should be propagated to extensions as well. + Here is the documentation about the `migration to react 18 `_. + +Testing with Jest +^^^^^^^^^^^^^^^^^ + +Jest has been updated to 29.2.0 (and *ts-jest* to 29.0.0). And therefore the jest configuration provided by +``@jupyterlab/testutils`` is compatible for that version. In particular: + +- The unmaintained reporter ``jest-summary-reporter`` has been replaced by the new default ``github-actions`` reporter. +- The helper ``flakyIt`` has been removed. You can use the new `jest.retryTimes `_ instead. + +With JupyterLab 4, we fixed circular dependencies due to the ``testutils`` package. So it is now only a facade to export +helpers from various core packages. The exported helpers are the same as before expect for: + +- ``NBTestUtils.DEFAULT_CONTENT``: Removed - you could imported from ``@jupyterlab/notebook/lib/testutils`` but we strongly advice not to and to use your own test data. +- ``NBTestUtils.DEFAULT_CONTENT_45``: Removed + +Testing with Galata +^^^^^^^^^^^^^^^^^^^ + +The in-page helpers are now in an JupyterLab extension to live in the common Webpack shared scoped. That new extension +is contained in the JupyterLab python package at ``jupyterlab.galata``. It requires to update your Jupyter server +configuration by adding the following line: + +.. code-block:: python + + import jupyterlab + c.LabApp.extra_labextensions_path = str(Path(jupyterlab.__file__).parent / "galata") + +.. note:: + + To ease configuration, we have introduce a new helper function ``jupyterlab.galata.configure_jupyter_server``. So you can + simplify the server configuration to be ``jupyterlab.galata.configure_jupyter_server(c)``. + +Here are the changes in the Javascript package ``@jupyterlab/galata`` from 4.x to 5.x: + * ``ContentsHelper`` and ``galata.newContentsHelper`` have new constructor arguments to use Playwright API request object: + ``new ContentsHelper(baseURL, page?, request?)`` -> ``new ContentsHelper(request?, page?)`` + ``galata.newContentsHelper(baseURL, page?, request?)`` -> ``galata.newContentsHelper(request?, page?)`` + you need to provide ``request`` or ``page``; they both are fixtures provided by Playwright. + * ``galata.Mock.clearRunners(baseURL, runners, type)`` -> ``galata.Mock.clearRunners(request, runners, type)`` + * In-pages helpers are now in an extension define in ``jupyterlab/galata/extension`` and + store in ``@jupyterlab/galata/lib/extension``. And the global object has been renamed ``window.galata`` instead + of ``window.galataip`` (it still exists but it is deprecated). + +Deprecated code removed +^^^^^^^^^^^^^^^^^^^^^^^ + +The following deprecated API's have been removed: + +- ``@jupyterlab/csvviewer``: ``CSVDelimiter.delimiterChanged`` has been removed - dead code. You can directly access the delimiter from the ``CSVViewer`` widget. +- ``@jupyterlab/mainmenu``: ``IJupyterLabMenu`` and ``JupyterLabMenu`` have been removed. You can use directly ``IRankedMenu`` and ``RankedMenu`` from ``@jupyterlab/ui-components`` +- ``@jupyterlab/notebook``: ``NotebookWidgetFactory`` default toolbar is now empty as the button helpers are deprecated. +- ``@jupyterlab/rendermime``: ``RenderMimeRegistry.IUrlResolverOptions`` does not accept ``session``; you must set the ``path`` (accessible through ``session.path``). +- ``@jupyterlab/ui-components``: + * ``RankedMenu.menu : Menu`` has been removed as ``RankedMenu`` inherits from ``Menu``. + * ``LabIconStyle.IProps`` does not accept ``kind`` nor ``justify``. You should use ``stylesheet`` or ``elementPosition`` respectively. + +Extension Development Changes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- The ``externalExtensions`` field in the ``dev_mode/package.json`` file corresponding to the ``@jupyterlab/application-top`` + ``private`` package has now been removed in ``4.0``. If you were using this field to develop source extensions against + a development build of JupyterLab, you should instead switch to the federated extensions system (via the ``--extensions-in-dev-mode`` flag) + or to using the ``--splice-source`` option. See :ref:`prebuilt_dev_workflow` and :ref:`source_dev_workflow` for more information. +- The ``webpack`` dependency in ``@jupyterlab/builder`` has been updated to ``5.72`` (or newer). Base rules have been updated to use the + `Asset Modules `_ instead of the previous ``file-loader``, ``raw-loader`` and ``url-loader``. + This might affect third-party extensions if they were relying on specific behaviors from these loaders. +- In JupyterLab 3.x, the CSS for a _disabled_ prebuilt extensions would still be loaded on the page. + This is no longer the case in JupyterLab 4.0. +- ``window.jupyterlab`` is not exposed anymore when starting JupyterLab with the ``--expose-app-in-browser`` flag. + Use ``window.jupyterapp`` instead. .. _extension_migration_3.5_3.6: @@ -20,6 +470,7 @@ target to ES2018 or add ``"ES2018"`` to the `TypeScript lib option `__. In addition, the shared models' package was moved to an external package called `@jupyter/ydoc -`__. ``@jupyterlab/shared-models`` has been kept -for backward compatibility (except in 3.6.0 and 3.6.1). It is now a proxy to ``@jupyter/ydoc@~0.2.2``; -the API is almost the same; see the required modification for the `example `_. +`__. All the extensions that depend on +``@jupyterlab/shared-models`` will need to update to depend in ``@jupyter/ydoc@~0.2.2``; the API should +be the same. **API Changes:** - To be able to fix RTC and make it stable. It was necessary to change the API and make a few breaking changes. These changes should not affect the vast majority of extensions. They will only affect a couple of extensions focused on RTC. @@ -86,42 +536,31 @@ The involved packages are: * ``WebSocketProvider.IOptions`` has a new optional attribute, ``user``. -- ``@jupyterlab/shared-models``: It is now a proxy to ``@jupyter/ydoc@~0.2.2``. - - A document model extending ``YDocument`` must define a change interface extending ``DocumentChange``. - - ``@jupyterlab/services``: * The interface ``IManager`` has a new optional property, ``user`` that implement `User.IManager <../api/interfaces/services.User.IManager.html>`_. * The ``ServiceManager`` class implements the optional property ``user`` from the ``IManager``. -**Future changes:** -Some of the behavior changes coming in JupyterLab 4.0 were made available behind a flag in JupyterLab 3.6: - -- In JupyterLab 3.x, the CSS for a _disabled_ prebuilt extensions is always loaded on the page. - This will no longer be the case in JupyterLab 4.0. To preview the impact of these changes on - your extension/theme start JupyterLab with ``--future-skip-styles-for-disabled`` flag. - .. _extension_migration_3.0_3.1: JupyterLab 3.0 to 3.1 --------------------- -Following semver rules, API are compatible. - New main and context menus customization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ JupyterLab 3.1 introduces a new way to hook commands into :ref:`mainmenu` and :ref:`context_menu`. It allows the final user to customize those menus through settings as it is already possible for the shortcuts. +Using the API is not recommended any longer except to create dynamic menus. Jest configuration update ^^^^^^^^^^^^^^^^^^^^^^^^^ If you are using jest to test your extension, some new ES6 packages dependencies are added to JupyterLab. -They need to be ignore when transforming the code with Jest. You will need to update the +They need to be ignore when transforming the code with Jest. You will need to update the ``transformIgnorePatterns`` to match: .. code:: @@ -142,13 +581,13 @@ For more information, have a look at :ref:`testing_with_jest`. .. note:: - Here is an example of pull request to update to JupyterLab 3.1 in ``@jupyterlab/git`` extension: + Here is an example of pull request to update to JupyterLab 3.1 in ``@jupyterlab/git`` extension: https://github.com/jupyterlab/jupyterlab-git/pull/979/files .. _extension_migration_2_3: -JupyterLab 2.x to 3.x +JupyterLab 2.x to 3.x --------------------- Here are some helpful tips for migrating an extension from JupyterLab 2.x to JupyterLab 3.x. @@ -293,7 +732,7 @@ Upgrading library versions The ``@phosphor/*`` libraries that JupyterLab 1.x uses have been renamed to ``@lumino/*``. Updating your ``package.json`` is straightforward. The easiest way to do this is to look in the -`JupyterLab core packages code base `__ +`JupyterLab core packages code base `__ and to simply adopt the versions of the relevant libraries that are used there. @@ -414,7 +853,7 @@ Using ``Session`` and ``SessionContext`` to manage kernel sessions For full API documentation and examples of how to use ``@jupyterlab/services``, - `consult the repository `__. + `consult the repository `__. ``ConsolePanel`` and ``NotebookPanel`` now expose a ``sessionContext: ISessionContext`` attribute that allows for a uniform way to @@ -449,6 +888,4 @@ Using the new icon system and ``LabIcon`` For full API documentation and examples of how to use the new icon support based on ``LabIcon`` from ``@jupyterlab/ui-components``, - `consult the repository `__. - - + `consult the repository `__. diff --git a/docs/source/extension/extension_points.rst b/docs/source/extension/extension_points.rst index f24f9f9e6b29..e5e57e9bc290 100644 --- a/docs/source/extension/extension_points.rst +++ b/docs/source/extension/extension_points.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. _developer-extension-points: Common Extension Points @@ -11,7 +14,7 @@ Following the list of core tokens is a guide for using some of JupyterLab's most However, it is not an exhaustive account of how to extend the application components, and more detailed descriptions of their public APIs may be found in the `JupyterLab <../api/index.html>`__ and -`Lumino `__ API documentation. +`Lumino `__ API documentation. .. contents:: Table of contents :local: @@ -19,6 +22,16 @@ and more detailed descriptions of their public APIs may be found in the .. _core_tokens: +Core Plugins +------------ + +The core packages of JupyterLab provide the following plugins. They can be +enabled or disabled using the command ``jupyter labextension enable `` or +``jupyter labextension disable ``. + +.. include:: plugins_list.rst + :parser: myst_parser.sphinx_ + Core Tokens ----------- @@ -26,113 +39,8 @@ The core packages of JupyterLab provide many services for plugins. The tokens for these services are listed here, along with short descriptions of when you might want to use the services in your extensions. -- ``@jupyterlab/application:IConnectionLost``: A service for invoking the dialog shown - when JupyterLab has lost its connection to the server. Use this if, for some reason, - you want to bring up the "connection lost" dialog under new circumstances. -- ``@jupyterlab/application:IInfo``: A service providing metadata about the current - application, including disabled extensions and whether dev mode is enabled. -- ``@jupyterlab/application:IPaths``: A service providing information about various - URLs and server paths for the current application. Use this service if you want to - assemble URLs to use the JupyterLab REST API. -- ``@jupyterlab/application:ILabStatus``: A service for interacting with the application busy/dirty - status. Use this if you want to set the application "busy" favicon, or to set - the application "dirty" status, which asks the user for confirmation before leaving the application page. -- ``@jupyterlab/application:ILabShell``: A service for interacting with the JupyterLab shell. - The top-level ``application`` object also has a reference to the shell, but it has a restricted - interface in order to be agnostic to different shell implementations on the application. - Use this to get more detailed information about currently active widgets and layout state. -- ``@jupyterlab/application:ILayoutRestorer``: A service providing application layout - restoration functionality. Use this to have your activities restored across - page loads. -- ``@jupyterlab/application:IMimeDocumentTracker``: A widget tracker for documents - rendered using a mime renderer extension. Use this if you want to list and interact - with documents rendered by such extensions. -- ``@jupyterlab/application:IRouter``: The URL router used by the application. - Use this to add custom URL-routing for your extension (e.g., to invoke - a command if the user navigates to a sub-path). -- ``@jupyterlab/apputils:ICommandPalette``: A service for the application command palette - in the left panel. Use this to add commands to the palette. -- ``@jupyterlab/apputils:ISplashScreen``: A service for the splash screen for the application. - Use this if you want to show the splash screen for your own purposes. -- ``@jupyterlab/apputils:IThemeManager``: A service for the theme manager for the application. This is used primarily in theme extensions to register new themes. -- ``@jupyterlab/apputils:IToolbarWidgetRegistry``: A registry for toolbar widgets. Require this - if you want to build the toolbar dynamically from a data definition (stored in settings for example). -- ``@jupyterlab/apputils:IWindowResolver``: A service for a window resolver for the - application. JupyterLab workspaces are given a name, which are determined using - the window resolver. Require this if you want to use the name of the current workspace. -- ``@jupyterlab/codeeditor:IEditorServices``: A service for the text editor provider - for the application. Use this to create new text editors and host them in your - UI elements. -- ``@jupyterlab/completer:ICompletionManager``: A service for the completion manager - for the application. Use this to allow your extension to invoke a completer. -- ``@jupyterlab/console:IConsoleTracker``: A widget tracker for code consoles. - Use this if you want to be able to iterate over and interact with code consoles - created by the application. -- ``@jupyterlab/console:IContentFactory``: A factory object that creates new code - consoles. Use this if you want to create and host code consoles in your own UI elements. -- ``@jupyterlab/docmanager:IDocumentManager``: A service for the manager for all - documents used by the application. Use this if you want to open and close documents, - create and delete files, and otherwise interact with the file system. -- ``@jupyterlab/docprovider:IDocumentProviderFactory``: A factory object that creates new providers for - shared documents. Use this if you want to create a provider for a new shared document. -- ``@jupyterlab/documentsearch:ISearchProviderRegistry``: A service for a registry of search - providers for the application. Plugins can register their UI elements with this registry - to provide find/replace support. -- ``@jupyterlab/filebrowser:IFileBrowserFactory``: A factory object that creates file browsers. - Use this if you want to create your own file browser (e.g., for a custom storage backend), - or to interact with other file browsers that have been created by extensions. -- ``@jupyterlab/fileeditor:IEditorTracker``: A widget tracker for file editors. - Use this if you want to be able to iterate over and interact with file editors - created by the application. -- ``@jupyterlab/htmlviewer:IHTMLViewerTracker``: A widget tracker for rendered HTML documents. - Use this if you want to be able to iterate over and interact with HTML documents - viewed by the application. -- ``@jupyterlab/imageviewer:IImageTracker``: A widget tracker for images. - Use this if you want to be able to iterate over and interact with images - viewed by the application. -- ``@jupyterlab/inspector:IInspector``: A service for adding contextual help to widgets (visible using "Show Contextual Help" from the Help menu). - Use this to hook into the contextual help system in your extension. -- ``@jupyterlab/launcher:ILauncher``: A service for the application activity launcher. - Use this to add your extension activities to the launcher panel. -- ``@jupyterlab/mainmenu:IMainMenu``: A service for the main menu bar for the application. - Use this if you want to add your own menu items or provide implementations for standardized menu items for specific activities. -- ``@jupyterlab/markdownviewer:IMarkdownViewerTracker``: A widget tracker for markdown - document viewers. Use this if you want to iterate over and interact with rendered markdown documents. -- ``@jupyterlab/notebook:INotebookTools``: A service for the ``Notebook Tools`` panel in the - right sidebar. Use this to add your own functionality to the panel. -- ``@jupyterlab/notebook:IContentFactory``: A factory object that creates new notebooks. - Use this if you want to create and host notebooks in your own UI elements. -- ``@jupyterlab/notebook:INotebookTracker``: A widget tracker for notebooks. - Use this if you want to be able to iterate over and interact with notebooks - created by the application. -- ``@jupyterlab/rendermime:IRenderMimeRegistry``: A service for the rendermime registry - for the application. Use this to create renderers for various mime-types in your extension. Many times it will be easier to create a `mime renderer extension <#mime-renderer-extensions>`__ rather than using this service directly. -- ``@jupyterlab/rendermime:ILatexTypesetter``: A service for the LaTeX typesetter for the - application. Use this if you want to typeset math in your extension. -- ``@jupyterlab/settingeditor:ISettingEditorTracker``: A widget tracker for setting editors. - Use this if you want to be able to iterate over and interact with setting editors - created by the application. -- ``@jupyterlab/settingregistry:ISettingRegistry``: A service for the JupyterLab settings system. - Use this if you want to store settings for your application. - See :ref:`schemaDir` for more information. -- ``@jupyterlab/statedb:IStateDB``: A service for the JupyterLab state database. - Use this if you want to store data that will persist across page loads. - See `state database <#state-database>`__ for more information. -- ``@jupyterlab/statusbar:IStatusBar``: A service for the status bar on the application. - Use this if you want to add new status bar items. -- ``@jupyterlab/terminal:ITerminalTracker``: A widget tracker for terminals. - Use this if you want to be able to iterate over and interact with terminals - created by the application. -- ``@jupyterlab/tooltip:ITooltipManager``: A service for the tooltip manager for the application. - Use this to allow your extension to invoke a tooltip. -- ``@jupyterlab/collaboration:IGlobalAwareness``: A service for the global awareness, providing information about other collaborators. -- ``@jupyterlab/collaboration:ICurrentUser``: A service for the current user information. - Use this if you want to access to the identity of the current connected user. -- ``@jupyterlab/collaboration:IUserMenu``: A service for the user menu on the application. - Use this if you want to add new items to the user menu. -- ``@jupyterlab/vdom:IVDOMTracker``: A widget tracker for virtual DOM (VDOM) documents. - Use this to iterate over and interact with VDOM document instances created by the application. - +.. include:: tokens_list.rst + :parser: myst_parser.sphinx_ Commands @@ -183,7 +91,7 @@ a string value or a function that returns a string value. There are several more options which can be passed into the command registry when adding new commands. These are documented -`here `__. +`here `__. After a command has been added to the application command registry you can add them to various places in the application user interface, @@ -261,19 +169,18 @@ A list of CSS selectors currently used by context menu commands is given in :ref Item must follow this definition: -.. literalinclude:: ../snippets/packages/settingregistry/src/plugin-schema.json +.. literalinclude:: ../snippets/packages/settingregistry/src/jupyter.lab.menus.json :language: json - :lines: 37-55 + :lines: 14-34 where ``menuItem`` definition is: -.. literalinclude:: ../snippets/packages/settingregistry/src/plugin-schema.json +.. literalinclude:: ../snippets/packages/settingregistry/src/menuItem.json :language: json - :lines: 158-196 The same example using the API is shown below. See the Lumino `docs -`__ +`__ for the item creation options. .. code:: typescript @@ -305,7 +212,7 @@ Alternatively, you can use a 'contextmenu' event listener and call ``event.stopPropagation`` to prevent the application context menu handler from being called (it is listening in the bubble phase on the ``document``). At this point you could show your own Lumino -`contextMenu `__, +`contextMenu `__, or simply stop propagation and let the system context menu be shown. This would look something like the following in a ``Widget`` subclass: @@ -363,7 +270,7 @@ browser supports overriding the behavior of this item. }, isVisible: () => tracker.currentWidget && - toArray(tracker.currentWidget.selectedItems()).length === 1, + Array.from(tracker.currentWidget.selectedItems()).length === 1, iconClass: 'jp-MaterialIcon jp-LinkIcon', label: 'Copy Shareable Link' }); @@ -406,7 +313,7 @@ the shortcut handler propagates up the DOM tree from the focused element and tests each element against the registered selectors. If a match is found, then that command is executed with the provided ``args``. Full documentation for the options for ``addKeyBinding`` can be found -`here `__. +`here `__. JupyterLab also provides integration with its settings system for keyboard shortcuts. Your extension can provide a settings schema with a ``jupyter.lab.shortcuts`` key, @@ -426,6 +333,31 @@ declaring default keyboard shortcuts for a command: Shortcuts added to the settings system will be editable by users. +From Jupyterlab version 3.1 onwards, it is possible to execute multiple commands with a single shortcut. +This requires you to define a keyboard shortcut for ``apputils:run-all-enabled`` command: + +.. code:: json + + { + "command": "apputils:run-all-enabled", + "keys": ["Accel T"], + "args": { + "commands": [ + "my-command-1", + "my-command-2" + ], + "args": [ + {}, + {} + ] + }, + "selector": "body" + } + +In this example ``my-command-1`` and ``my-command-2`` are passed in ``args`` +of ``apputils:run-all-enabled`` command as ``commands`` list. +You can optionally pass the command arguments of ``my-command-1`` and ``my-command-2`` in ``args`` +of ``apputils:run-all-enabled`` command as ``args`` list. Launcher -------- @@ -451,7 +383,7 @@ Jupyter Front-End Shell ----------------------- The Jupyter front-end -`shell <../api/interfaces/application.jupyterfrontend.ishell.html>`__ +`shell <../api/interfaces/application.JupyterFrontEnd.IShell.html>`__ is used to add and interact with content in the application. The ``IShell`` interface provides an ``add()`` method for adding widgets to the application. In JupyterLab, the application shell consists of: @@ -464,6 +396,22 @@ In JupyterLab, the application shell consists of: - A ``bottom`` area for things like status bars. - A ``header`` area for custom elements. +Top Area +^^^^^^^^ + +The top area is intended to host most persistent user interface elements that span the whole session of a user. +A toolbar named **TopBar** is available on the right of the main menu bar. For example, JupyterLab adds a user +dropdown to that toolbar when started in ``collaborative`` mode. + +See :ref:`generic toolbars ` to see how to add a toolbar or a custom widget to a toolbar. + +You can use a numeric rank to control the ordering of top bar items in the settings; see :ref:`Toolbar definitions `. + +JupyterLab adds a spacer widget to the top bar at rank ``50`` by default. +You can then use the following guidelines to place your items: + +* ``rank <= 50`` to place items to the left side in the top bar +* ``rank > 50`` to place items to the right side in the top bar Left/Right Areas ^^^^^^^^^^^^^^^^ @@ -570,6 +518,9 @@ Here is the list of default menu ids: - Edit menu: ``jp-mainmenu-edit`` - View menu: ``jp-mainmenu-view`` + + * Appearance submenu: ``jp-mainmenu-view-appearance`` + - Run menu: ``jp-mainmenu-run`` - Kernel menu: ``jp-mainmenu-kernel`` - Tabs menu: ``jp-mainmenu-tabs`` @@ -580,15 +531,14 @@ The default main menu is defined in the ``mainmenu-extension`` package settings. A menu must respect the following schema: -.. literalinclude:: ../snippets/packages/settingregistry/src/plugin-schema.json +.. literalinclude:: ../snippets/packages/settingregistry/src/jupyter.lab.menus.json :language: json - :lines: 101-157 + :lines: 5-13 And an item must follow: -.. literalinclude:: ../snippets/packages/settingregistry/src/plugin-schema.json +.. literalinclude:: ../snippets/packages/settingregistry/src/menu.json :language: json - :lines: 158-196 Menus added to the settings system will be editable by users using the ``mainmenu-extension`` settings. In particular, they can be disabled at the item or the menu level by setting the @@ -609,7 +559,7 @@ Adding a New Menu ~~~~~~~~~~~~~~~~~ To add a new menu to the menu bar, you need to create a new -`Lumino menu `__. +`Lumino menu `__. You can then add commands to the menu in a similar way to the command palette, and add that menu to the main menu bar: @@ -671,23 +621,12 @@ Here is an example of using the ``closeAndCleaners`` semantic menu item: .. code:: typescript mainMenu.fileMenu.closeAndCleaners.add({ - tracker, - action: 'Shutdown', - name: 'My Activity', - closeAndCleanup: current => { - current.close(); - return current.shutdown(); - } + id: 'notebook:close-and-shutdown', + isEnabled: (w: Widget) => tracker.currentWidget !== null && tracker.has(w) }); In this example, ``tracker`` is a :ref:`widget-tracker`, which allows the menu -item to determine whether to delegate the menu command to your activity, -``name`` is a name given to your activity in the menu label, -``action`` is a verb given to the cleanup operation in the menu label, -and ``closeAndCleanup`` is the actual function that performs the cleanup operation. -So if the current application activity is held in the ``tracker``, -then the menu item will show ``Shutdown My Activity``, and delegate to the -``closeAndCleanup`` function that was provided. +item to determine whether to delegate the menu command to your activity, and ``id`` is a the command identifier. More examples for how to register semantic menu items are found throughout the JupyterLab code base. The available semantic menu items are: @@ -756,20 +695,20 @@ A typical example is the notebook toolbar as in the snippet below: let toolbarFactory: | ((widget: NotebookPanel) => DocumentRegistry.IToolbarItem[]) | undefined; - + // Register notebook toolbar specific widgets if (toolbarRegistry) { toolbarRegistry.registerFactory(FACTORY, 'cellType', panel => ToolbarItems.createCellTypeItem(panel, translator) ); - + toolbarRegistry.registerFactory( FACTORY, 'kernelStatus', panel => Toolbar.createKernelStatusItem(panel.sessionContext, translator) ); - // etc... - + // etc... + if (settingRegistry) { // Create the factory toolbarFactory = createToolbarFactory( @@ -783,7 +722,7 @@ A typical example is the notebook toolbar as in the snippet below: ); } } - + const factory = new NotebookWidgetFactory({ name: FACTORY, fileTypes: ['notebook'], @@ -795,19 +734,21 @@ A typical example is the notebook toolbar as in the snippet below: }); app.docRegistry.addWidgetFactory(factory); -The registry ``registerFactory`` method allows an extension to provide special widget for a unique pair +The registry ``registerFactory`` method allows an extension to provide special widget for a unique pair (factory name, toolbar item name). Then the helper ``createToolbarFactory`` can be used to extract the toolbar definition from the settings and build the factory to pass to the widget factory. The default toolbar items can be defined across multiple extensions by providing an entry in the ``"jupyter.lab.toolbars"`` mapping. For example for the notebook panel: +.. _toolbar-settings-definition: + .. code:: js - + "jupyter.lab.toolbars": { "Notebook": [ // Factory name // Item with non-default widget - it must be registered within an extension - { + { "name": "save", // Unique toolbar item name "rank": 10 // Item rank }, @@ -821,7 +762,7 @@ mapping. For example for the notebook panel: { "name": "restart", "command": "kernelmenu:restart", "rank": 32 }, { "name": "restart-and-run", - "command": "runmenu:restart-and-run-all", + "command": "notebook:restart-run-all", "rank": 33 // The default rank is 50 }, { "name": "cellType", "rank": 40 }, @@ -866,11 +807,14 @@ The current widget factories supporting the toolbar customization are: - ``CSVTable``: CSV (Comma Separated Value) Viewer toolbar - ``TSVTable``: TSV (Tabulation Separated Value) Viewer toolbar -Add the toolbar item must follow this definition: +.. _toolbar-item: -.. literalinclude:: ../snippets/packages/settingregistry/src/plugin-schema.json +And the toolbar item must follow this definition: + +.. literalinclude:: ../snippets/packages/settingregistry/src/toolbarItem.json :language: json - :lines: 207-252 + +.. _generic-toolbar: Generic Widget with Toolbar ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -879,9 +823,11 @@ The logic detailed in the previous section can be used to customize any widgets The additional keys used in ``jupyter.lab.toolbars`` settings attributes are: +- ``Cell``: Cell toolbar - ``FileBrowser``: Default file browser panel toolbar items +- ``TopBar``: Top area toolbar (right of the main menu bar) -Here is an example for enabling that definition on a widget: +Here is an example for enabling a toolbar on a widget: .. code:: typescript @@ -905,16 +851,21 @@ Here is an example for enabling that definition on a widget: // - Link the widget toolbar and its definition from the settings setToolbar( - browser, + browser, // This widget is the one passed to the toolbar item factory createToolbarFactory( toolbarRegistry, settings, 'FileBrowser', // Factory name plugin.id, translator - ) + ), + // You can explicitly pass the toolbar widget if it is not accessible as `toolbar` attribute + // toolbar, ); +See :ref:`Toolbar definitions ` example on how to define the toolbar +items in the settings. + .. _widget-tracker: Widget Tracker @@ -972,3 +923,38 @@ a plugin: return foo; } }; + +LSP Features +-------------- + +JupyterLab provides an infrastructure to communicate with the language servers. If the LSP services are activated and users have language servers installed, JupyterLab will start the language servers for the language of the opened notebook or file. Extension authors can access the virtual documents and the associated LSP connection of opened document by requiring the ``ILSPDocumentConnectionManager`` token from ``@jupyterlab/lsp``. + +Here is an example for making requests to the language server. + +.. code:: typescript + + const plugin: JupyterFrontEndPlugin = { + id, + autoStart: true, + requires: [ILSPDocumentConnectionManager], + activate: async (app: JupyterFrontEnd, manager: ILSPDocumentConnectionManager): Promise => { + + // Get the path to the opened notebook of file + const path = ... + + // Get the widget adapter of opened document + const adapter = manager.adapters.get(path); + if (!adapter) { + return + } + // Get the associated virtual document of the opened document + const virtualDocument = adapter.virtualDocument; + + // Get the LSP connection of the virtual document. + const connection = manager.connections.get(document.uri); + ... + // Send completion request to the language server + const response = await connection.clientRequests['textDocument/completion'].request(params); + ... + } + }; diff --git a/docs/source/extension/extension_tutorial.rst b/docs/source/extension/extension_tutorial.rst index 68e33ed8d44e..46f0e2e5566f 100644 --- a/docs/source/extension/extension_tutorial.rst +++ b/docs/source/extension/extension_tutorial.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. _extension_tutorial: Extension Tutorial @@ -17,7 +20,7 @@ By working through this tutorial, you'll learn: - How to set up an extension development environment from scratch on a Linux or OSX machine. (You'll need to modify the commands slightly if you are on Windows.) - How to start an extension project from - `jupyterlab/extension-cookiecutter-ts `__ + `jupyterlab/extension-template `__ - How to iteratively code, build, and load your extension in JupyterLab - How to version control your work with git - How to release your extension for others to enjoy @@ -47,8 +50,8 @@ Install NodeJS, JupyterLab, etc. in a conda environment Next create a conda environment that includes: -1. the latest release of JupyterLab -2. `cookiecutter `__, the tool +1. The latest release of JupyterLab +2. `copier `__ and some dependencies, the tool you'll use to bootstrap your extension project structure (this is a Python tool which we'll install using conda below). 3. `NodeJS `__, the JavaScript runtime you'll use to @@ -63,7 +66,7 @@ new environment named ``jupyterlab-ext``. .. code:: bash - conda create -n jupyterlab-ext --override-channels --strict-channel-priority -c conda-forge -c nodefaults jupyterlab=3 cookiecutter nodejs jupyter-packaging git + conda create -n jupyterlab-ext --override-channels --strict-channel-priority -c conda-forge -c nodefaults jupyterlab=4 nodejs=18 git copier=7 jinja2-time Now activate the new environment so that all further commands you run work out of that environment. @@ -81,64 +84,74 @@ Create a repository ------------------- Create a new repository for your extension (see, for example, the -`GitHub instructions `__. This is an +`GitHub instructions `__). This is an optional step, but highly recommended if you want to share your extension. Create an extension project --------------------------- -Initialize the project from a cookiecutter -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Initialize the project from the template +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Next use cookiecutter to create a new project for your extension. +Next use copier to create a new project for your extension. This will create a new folder for your extension in your current directory. .. code:: bash - cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts + mkdir my_first_extension + cd my_first_extension + copier copy https://github.com/jupyterlab/extension-template . -When prompted, enter values like the following for all of the cookiecutter +When prompted, enter values like the following for all of the template prompts (``apod`` stands for Astronomy Picture of the Day, the NASA service we are using to fetch pictures). .. code:: bash - Select kind: - 1 - frontend - 2 - server - 3 - theme - Choose from 1, 2, 3 [1]: 1 - author_name [My Name]: Your Name - author_email [me@test.com]: your@name.org - labextension_name [myextension]: jupyterlab_apod - python_name [jupyterlab_apod]: jupyterlab_apod - project_short_description [A JupyterLab extension.]: Show a random NASA Astronomy Picture of the Day in a JupyterLab panel - has_settings [n]: n - has_binder [n]: y - test [y]: y - repository [https://github.com/github_username/jupyterlab_apod]: https://github.com/github_username/jupyterlab_apod + What is your extension kind? + (Use arrow keys) + frontend + Extension author name + Your Name + Extension author email + your@name.org + JavaScript package name + jupyterlab_apod + Python package name + jupyterlab_apod + Extension short description + Show a random NASA Astronomy Picture of the Day in a JupyterLab panel + Does the extension have user settings? + N + Do you want to set up Binder example? + Y + Do you want to set up test for the extension? + Y + Git remote repository URL + https://github.com/github_username/jupyterlab_apod -Notes: +.. note:: -- If you are not using a repository, leave the repository field blank. You can come back and edit the repository field in the ``package.json`` file later. + - If you are not using a repository, leave the repository field blank. You can come back and edit the repository field in the ``package.json`` file later. + - If you are using the latest version of the template, you will notice that tests are included in the template. If you don't want to include them just answer ``n`` to the test prompt. -- If you are using the latest version of ``cookiecutter`` you will notice that tests are included in the template. If you don't want to include them just insert ``n`` . +List the files. -Change to the directory the cookiecutter created and list the files. +.. code-block:: shell -.. code:: bash - - cd jupyterlab_apod - ls + ls -a You should see a list like the following. -:: +.. code-block:: - CHANGELOG.md README.md babel.config.js install.json jupyterlab_apod pyproject.toml src tsconfig.json - LICENSE RELEASE.md binder jest.config.js package.json setup.py style ui-tests + .copier-answers.yml .github .gitignore .prettierignore .yarnrc.yml + babel.config.js jest.config.js pyproject.toml src ui-tests + binder jupyterlab_apod README.md style yarn.lock + CHANGELOG.md LICENSE RELEASE.md tsconfig.json + install.json package.json setup.py tsconfig.test.json Commit what you have to git ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -150,14 +163,15 @@ initialize it as a git repository and commit the current code. git init git add . - git commit -m 'Seed apod project from cookiecutter' + git commit -m 'Seed apod project from extension template' -Note: This step is not technically necessary, but it is good practice to -track changes in version control system in case you need to rollback to -an earlier version or want to collaborate with others. You -can compare your work throughout this tutorial with the commits in a -reference version of ``jupyterlab_apod`` on GitHub at -https://github.com/jupyterlab/jupyterlab_apod. +.. note:: + This step is not technically necessary, but it is good practice to + track changes in version control system in case you need to rollback to + an earlier version or want to collaborate with others. You + can compare your work throughout this tutorial with the commits in a + reference version of ``jupyterlab_apod`` on GitHub at + https://github.com/jupyterlab/jupyterlab_apod. Build and install the extension for development @@ -184,7 +198,7 @@ JupyterLab: .. note:: - On Windows, symbolic links can be activated on Windows 10 for Python version 3.8 or higher + On Windows, symbolic links can be activated on Windows 10 or above for Python version 3.8 or higher by activating the 'Developer Mode'. That may not be allowed by your administrators. See `Activate Developer Mode on Windows `__ for instructions. @@ -213,10 +227,12 @@ After you reload the page with the console open, you should see a message that s ``JupyterLab extension jupyterlab_apod is activated!`` in the console. If you do, congratulations, you're ready to start modifying the extension! If not, go back make sure you didn't miss a step, and `reach -out `__ if you're stuck. +out `__ if you're stuck. + +.. note:: -Note: Leave the terminal running the ``jupyter lab`` command open and running -JupyterLab to see the effects of changes below. + Leave the terminal running the ``jupyter lab`` command open and running + JupyterLab to see the effects of changes below. Add an Astronomy Picture of the Day widget @@ -248,13 +264,14 @@ Locate the ``plugin`` object of type ``JupyterFrontEndPlugin``. Change the definition so that it reads like so: .. code-block:: typescript - :emphasize-lines: 5,7-8,10 + :emphasize-lines: 5,8-9,11 /** * Initialization data for the jupyterlab_apod extension. */ const plugin: JupyterFrontEndPlugin = { id: 'jupyterlab-apod', + description: 'Show a random NASA Astronomy Picture of the Day in a JupyterLab panel.', autoStart: true, requires: [ICommandPalette], activate: (app: JupyterFrontEnd, palette: ICommandPalette) => { @@ -277,8 +294,7 @@ repository root folder to install the dependencies and save them to your .. code:: bash - jlpm add @jupyterlab/apputils - jlpm add @jupyterlab/application + jlpm add @jupyterlab/apputils @jupyterlab/application Finally, run the following to rebuild your extension. @@ -306,7 +322,7 @@ build command for errors and correct your code. ICommandPalette: Palette {_palette: CommandPalette} Note that we had to run ``jlpm run build`` in order for the bundle to -update. This command does two things: compiles the TypeScript files in `src/` +update. This command does two things: compiles the TypeScript files in ``src/``` into JavaScript files in ``lib/`` (``jlpm run build``), then bundles the JavaScript files in ``lib/`` into a JupyterLab extension in ``jupyterlab_apod/static`` (``jlpm run build:extension``). If you wish to avoid @@ -339,10 +355,11 @@ only modifying the contents of that function, so make sure your braces match, and leave the* ``export default plugin`` *part lower down intact)*: .. code-block:: typescript - :emphasize-lines: 5-41 + :emphasize-lines: 6-42 const plugin: JupyterFrontEndPlugin = { id: 'jupyterlab-apod', + description: 'Show a random NASA Astronomy Picture of the Day in a JupyterLab panel.', autoStart: true, requires: [ICommandPalette], activate: (app: JupyterFrontEnd, palette: ICommandPalette) => { @@ -418,7 +435,7 @@ The single *Astronomy Picture* tab should come to the foreground. If your widget is not behaving, compare your code with the reference project state at the `01-show-a-panel -tag `__. +tag `__. Once you've got everything working properly, git commit your changes and carry on. @@ -548,7 +565,7 @@ of these problems in the upcoming sections. If you don't see a image at all, compare your code with the `02-show-an-image -tag `__ +tag `__ in the reference project. When it's working, make another git commit. .. code:: bash @@ -662,7 +679,7 @@ of the image. If anything is not working correctly, compare your code with the reference project `03-style-and-attribute -tag `__. +tag `__. When everything is working as expected, make another commit. .. code:: bash @@ -838,7 +855,7 @@ image. If anything is not working correctly, compare your code with the `04-refactor-and-refresh -tag `__ +tag `__ to debug. Once it is working properly, commit it. .. code:: bash @@ -877,14 +894,15 @@ entire list of import statements looks like the following (Adding import { Widget } from '@lumino/widgets'; Then add the ``ILayoutRestorer`` interface to the ``JupyterFrontEndPlugin`` -definition. This addition passes the global ``LayoutRestorer`` as the +definition as ``optional``. This addition passes the global ``LayoutRestorer`` as the third parameter of the ``activate`` function. .. code-block:: typescript - :emphasize-lines: 5 + :emphasize-lines: 6 const plugin: JupyterFrontEndPlugin = { id: 'jupyterlab-apod', + description: 'Show a random NASA Astronomy Picture of the Day in a JupyterLab panel.', autoStart: true, requires: [ICommandPalette], optional: [ILayoutRestorer], @@ -893,8 +911,8 @@ third parameter of the ``activate`` function. Here ``ILayoutRestorer`` is specified as an ``optional`` token, as the corresponding service might not be available in a customized JupyterLab distribution that does not provide layout restoration -functionalities. Having it ``optional`` makes it a nice-to-have, and lets your extension be loaded -in more applications. +functionalities. Having it ``optional`` make it a nice to have, and enable your extension to be loaded +in more JupyterLab based applications. .. note:: @@ -905,9 +923,11 @@ Finally, rewrite the ``activate`` function so that it: 1. Declares a widget variable, but does not create an instance immediately. -2. Constructs a ``WidgetTracker`` and tells the ``ILayoutRestorer`` +2. Adds the global ``LayoutRestorer`` as the third parameter of the ``activate`` function. + This parameter is declared as ``ILayoutRestorer | null`` since the token is specified as ``optional``. +3. Constructs a ``WidgetTracker`` and tells the ``ILayoutRestorer`` to use it to save/restore panel state. -3. Creates, tracks, shows, and refreshes the widget panel appropriately. +4. Creates, tracks, shows, and refreshes the widget panel appropriately. .. code-block:: typescript @@ -974,7 +994,7 @@ after the refresh. The completed extension, showing the `Astronomy Picture of the Day for 24 Jul 2015 `__. Refer to the `05-restore-panel-state -tag `__ +tag `__ if your extension is not working correctly. Make a commit when the state of your extension persists properly. @@ -991,8 +1011,8 @@ of this tutorial. Packaging your extension ------------------------ -JupyterLab extensions for JupyterLab 3.0 can be distributed as Python -packages. The cookiecutter template we used contains all of the Python +JupyterLab extensions for JupyterLab 3.0 and above can be distributed as Python +packages. The extension template we used contains all of the Python packaging instructions in the ``pyproject.toml`` file to wrap your extension in a Python package. Before generating a package, we first need to install ``build``. @@ -1066,7 +1086,7 @@ You may want to also publish your extension as a JavaScript package to the Automated Releases ^^^^^^^^^^^^^^^^^^ -If you used the cookiecutter to bootstrap your extension, the repository should already +If you used the template to bootstrap your extension, the repository should already be compatible with the `Jupyter Releaser `_. The Jupyter Releaser provides a set of GitHub Actions Workflows to: diff --git a/docs/source/extension/images/active-markdown-cell-dom.svg b/docs/source/extension/images/active-markdown-cell-dom.svg new file mode 100644 index 000000000000..f92beb918bd3 --- /dev/null +++ b/docs/source/extension/images/active-markdown-cell-dom.svg @@ -0,0 +1,4 @@ + + + +
    .jp-Cell .jp-MarkdownCell .jp-Notebook-Cell .jp-mod-active
    .jp-Cell .jp-MarkdownCell .jp-Notebook-Cell .jp-mod-active
    .jp-CellHeader .jp-Cell-header
    .jp-CellHeader .jp-Cell-header
    .jp-Cell-inputWrapper
    .jp-Cell-inputWrapper
    .jp-CellFooter .jp-Cell-footer
    .jp-CellFooter .jp-Cell-footer
    .jp-Collapser
    .jp-InputCollapser
    .jp-Cell-inputCollapser
    .jp-Collapser...
    .jp-InputArea .jp-Cell-inputArea
    .jp-InputArea .jp-Cell-inputArea
    .jp-CodeMirrorEditor .jp-Editor .jp-InputAreaEditor
    .jp-CodeMirrorEditor .jp-Editor .jp-InputAreaEditor
    .jp-InputPrompt
    .jp-InputAreaPrompt
    .jp-InputPrompt...
    Viewer does not support full SVG 1.1
    diff --git a/docs/source/extension/images/code-cell-dom.svg b/docs/source/extension/images/code-cell-dom.svg new file mode 100644 index 000000000000..4ad71cfb2c2d --- /dev/null +++ b/docs/source/extension/images/code-cell-dom.svg @@ -0,0 +1,4 @@ + + + +
    .jp-Cell .jp-CodeCell .jp-Notebook-Cell
    .jp-Cell .jp-CodeCell .jp-Notebook-Cell
    .jp-CellHeader .jp-Cell-header
    .jp-CellHeader .jp-Cell-header
    .jp-Cell-inputWrapper
    .jp-Cell-inputWrapper
    .jp-CellFooter .jp-Cell-footer
    .jp-CellFooter .jp-Cell-footer
    .jp-Cell-outputWrapper
    .jp-Cell-outputWrapper
    .jp-Collapser
    .jp-InputCollapser
    .jp-Cell-inputCollapser
    .jp-Collapser...
    .jp-Collapser
    .jp-OutputCollapser
    .jp-Cell-outputCollapser
    .jp-Collapser...
    .jp-InputArea .jp-Cell-inputArea
    .jp-InputArea .jp-Cell-inputArea
    .jp-CodeMirrorEditor .jp-Editor .jp-InputAreaEditor
    .jp-CodeMirrorEditor .jp-Editor .jp-InputAreaEditor
    .jp-InputPrompt
    .jp-InputAreaPrompt
    .jp-InputPrompt...
    .jp-OutputArea .jp-Cell-outputArea
    .jp-OutputArea .jp-Cell-outputArea
    .jp-outputArea-child
    .jp-outputArea-child
    .jp-outputArea-child
    .jp-outputArea-child
    .jp-OutputPrompt
    .jp-OutputAreaPrompt
    .jp-OutputPrompt...
    .jp-OutputArea-output
    .jp-OutputArea-output
    .jp-OutputArea-output
    .jp-OutputArea-output
    .jp-OutputPrompt
    .jp-OutputAreaPrompt
    .jp-OutputPrompt...
    Viewer does not support full SVG 1.1
    diff --git a/docs/source/extension/images/rendered-markdown-cell-dom.svg b/docs/source/extension/images/rendered-markdown-cell-dom.svg new file mode 100644 index 000000000000..611b94e031b3 --- /dev/null +++ b/docs/source/extension/images/rendered-markdown-cell-dom.svg @@ -0,0 +1,4 @@ + + + +
    .jp-Cell .jp-MarkdownCell .jp-Notebook-Cell .jp-mod-rendered
    .jp-Cell .jp-MarkdownCell .jp-Notebook-Cell .jp-mod-rendered
    .jp-CellHeader .jp-Cell-header
    .jp-CellHeader .jp-Cell-header
    .jp-Cell-inputWrapper
    .jp-Cell-inputWrapper
    .jp-CellFooter .jp-Cell-footer
    .jp-CellFooter .jp-Cell-footer
    .jp-Collapser
    .jp-InputCollapser
    .jp-Cell-inputCollapser
    .jp-Collapser...
    .jp-InputArea .jp-Cell-inputArea
    .jp-InputArea .jp-Cell-inputArea
    .jp-CodeMirrorEditor .jp-Editor .jp-InputAreaEditor
    (invisible)
    .jp-CodeMirrorEditor...
    .jp-InputPrompt
    .jp-InputAreaPrompt
    .jp-InputPrompt...
    .jp-RenderedHTMLCommon .jp-RenderedMarkdown .jp-MarkdownOutput
    .jp-RenderedHTMLCommon .jp-RenderedMarkdown .jp-MarkdownOutput
    Viewer does not support full SVG 1.1
    diff --git a/docs/source/extension/internationalization.rst b/docs/source/extension/internationalization.rst index 2a710d2bb885..cc77756b183e 100644 --- a/docs/source/extension/internationalization.rst +++ b/docs/source/extension/internationalization.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + Internationalization and Localization ===================================== @@ -31,7 +34,7 @@ To internationalize your extension, the following tasks are required: Domain are normalized by replacing ``-`` with ``_`` characters. -3. Wraps all translatable strings with one of the `gettext functions `_. +3. Wraps all translatable strings with one of the `gettext functions `_. Examples: diff --git a/docs/source/extension/notebook.rst b/docs/source/extension/notebook.rst index 7c60fe394ef0..67a3ad9d7738 100644 --- a/docs/source/extension/notebook.rst +++ b/docs/source/extension/notebook.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + Notebook ======== @@ -19,9 +22,9 @@ The most complicated plugin included in the **JupyterLab application** is the **Notebook plugin**. The -`NotebookWidgetFactory <../api/classes/notebook.notebookwidgetfactory-1.html>`__ +`NotebookWidgetFactory <../api/classes/notebook.NotebookWidgetFactory-1.html>`__ constructs a new -`NotebookPanel <../api/classes/notebook.notebookpanel-1.html>`__ +`NotebookPanel <../api/classes/notebook.NotebookPanel-1.html>`__ from a model and populates the toolbar with default widgets. Structure of the Notebook plugin @@ -34,11 +37,11 @@ Model ^^^^^ The -`NotebookModel <../api/classes/notebook.notebookmodel-1.html>`__ +`NotebookModel <../api/classes/notebook.NotebookModel-1.html>`__ contains an observable list of cells. A `cell -model <../api/classes/cells.cellmodel-1.html>`__ +model <../api/classes/cells.CellModel-1.html>`__ can be: - a code cell @@ -64,10 +67,12 @@ Metadata """""""" The notebook model and the cell model (i.e. notebook cells) support -getting and setting metadata through an -`IObservableJSON <../api/modules/observables.iobservablejson.html>`__ -object. You can use this to get and set notebook/cell metadata, -as well as subscribe to changes to it. +getting and setting metadata through method ``getMetadata``, ``setMetadata`` +and ``deleteMetadata`` (see `NotebookModel <../api/classes/notebook.NotebookModel-1.html>`__ +and `cell model <../api/classes/cells.CellModel-1.html>`__). +You can listen for changes in the metadata through the ``sharedModel.metadataChanged`` attribute +(see `cell shared model `__ +and `notebook shared model `__). Notebook widget ^^^^^^^^^^^^^^^ @@ -77,13 +82,13 @@ a new NotebookPanel from the model. The NotebookPanel widget is added to the DockPanel. The **NotebookPanel** contains: - a - `Toolbar <../api/classes/apputils.toolbar-1.html>`__ + `Toolbar <../api/classes/ui_components.Toolbar-1.html>`__ - a `Notebook - widget <../api/classes/notebook.notebook-2.html>`__. + widget <../api/classes/notebook.Notebook-1.html>`__. The NotebookPanel also adds completion logic. -The **NotebookToolbar** maintains a list of widgets to add to the +The **Notebook toolbar** maintains a list of widgets to add to the toolbar. The **Notebook widget** contains the rendering of the notebook and handles most of the interaction logic with the notebook itself (such as keeping track of interactions such as selected and active cells and @@ -96,7 +101,7 @@ Higher level actions using NotebookActions """""""""""""""""""""""""""""""""""""""""" Higher-level actions are contained in the -`NotebookActions <../api/classes/notebook.notebookactions-1.html>`__ +`NotebookActions <../api/classes/notebook.NotebookActions-1.html>`__ namespace, which has functions, when given a notebook widget, to run a cell and select the next cell, merge or split cells at the cursor, delete selected cells, etc. @@ -105,27 +110,58 @@ Widget hierarchy """""""""""""""" A Notebook widget contains a list of `cell -widgets <../api/classes/cells.cell-1.html>`__, +widgets <../api/classes/cells.Cell-1.html>`__, corresponding to the cell models in its cell list. - Each cell widget contains an - `InputArea <../api/classes/cells.inputarea-1.html>`__, + `InputArea <../api/classes/cells.InputArea-1.html>`__, - - which contains n - `CodeEditorWrapper <../api/classes/codeeditor.codeeditorwrapper-1.html>`__, + - which contains a + `CodeEditorWrapper <../api/classes/codeeditor.CodeEditorWrapper-1.html>`__, - which contains a JavaScript CodeMirror instance. A -`CodeCell <../api/classes/cells.codecell-1.html>`__ +`CodeCell <../api/classes/cells.CodeCell-1.html>`__ also contains an -`OutputArea <../api/classes/outputarea.outputarea-2.html>`__. +`OutputArea <../api/classes/outputarea.OutputArea-1.html>`__. An OutputArea is responsible for rendering the outputs in the -`OutputAreaModel <../api/classes/outputarea.outputareamodel-1.html>`__ +`OutputAreaModel <../api/classes/outputarea.OutputAreaModel-1.html>`__ list. An OutputArea uses a notebook-specific -`RenderMimeRegistry <../api/classes/rendermime.rendermimeregistry-1.html>`__ +`RenderMimeRegistry <../api/classes/rendermime.RenderMimeRegistry-1.html>`__ object to render ``display_data`` output messages. +The Notebook widget is represented in the DOM with a ``
    `` element +with CSS classes ``jp-Notebook`` and ``jp-NotebookPanel-notebook``. +It contains a sequence of cells widgets. + + - Code cells have the following DOM structure: + + .. image:: images/code-cell-dom.svg + + - Rendered markdown cells have the following DOM structure: + + .. image:: images/rendered-markdown-cell-dom.svg + + - Active markdown cells have the following DOM structure: + + .. image:: images/active-markdown-cell-dom.svg + +.. note:: + The default nbconvert template for the HTML exporter produces the same DOM + as the JupyterLab notebook, allowing for the JupyterLab CSS to be used directly. + In JupyterLab, input areas are rendered with the CodeMirror, with a custom theme + making use of the CSS variables of JupyterLab. + In the case of nbconvert, code cells are rendered using the Pygments Python + library, which produces static HTML with syntax highlighting. The + `jupyterlab_pygments `_ + Pygments theme mimicks the default CodeMirror theme of JupyterLab. + +.. note:: + The SVG figures presenting the DOM structures of the different cell types + were produced with Draw.io, and contain the metadata allowing them to be + directly opened and edited with Draw.io. + Rendering output messages """"""""""""""""""""""""" @@ -154,11 +190,11 @@ Adding a button to the toolbar ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Since JupyterLab 3.2, adding toolbar item can be done using a :ref:`toolbar-registry` and settings. In particular -for the notebook, if the button is linked to a new command, you can add a button in the toolbar using the +for the notebook, if the button is linked to a new command, you can add a button in the toolbar using the following JSON snippet in your extension settings file: .. code:: js - + "jupyter.lab.toolbars": { "Notebook": [ // Widget factory name for which you want to add a toolbar item. // Item with default button widget triggering a command @@ -171,20 +207,21 @@ You may add a ``rank`` attribute to modify the item position (the default value Adding a widget to the notebook header ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Start from the cookie cutter extension template. +Start from the extension template. -:: +.. code-block:: shell - pip install cookiecutter - cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts - cd my_cookie_cutter_name + pip install "copier~=8.0" jinja2-time + mkdir myextension + cd myextension + copier copy --UNSAFE https://github.com/jupyterlab/extension-template . Install the dependencies. Note that extensions are built against the released npm packages, not the development versions. -:: +.. code-block:: shell - jlpm add -D @jupyterlab/notebook @jupyterlab/application @jupyterlab/ui-components @jupyterlab/docregistry @lumino/disposable @lumino/widgets --legacy-peer-deps + jlpm add -D @jupyterlab/notebook @jupyterlab/application @jupyterlab/ui-components @jupyterlab/docregistry @lumino/disposable @lumino/widgets Copy the following to ``src/index.ts``: @@ -199,9 +236,7 @@ Copy the following to ``src/index.ts``: JupyterFrontEndPlugin } from '@jupyterlab/application'; - import { - DocumentRegistry - } from '@jupyterlab/docregistry'; + import { DocumentRegistry } from '@jupyterlab/docregistry'; import { NotebookPanel, INotebookModel } from '@jupyterlab/notebook'; @@ -211,6 +246,7 @@ Copy the following to ``src/index.ts``: const plugin: JupyterFrontEndPlugin = { activate, id: 'my-extension-name:widgetPlugin', + description: 'Add a widget to the notebook header.', autoStart: true }; @@ -266,7 +302,7 @@ Copy the following to ``src/index.ts``: And the following to ``style/base.css``: -.. code:: css +.. code-block:: css .jp-myextension-myheader { min-height: 20px; @@ -276,29 +312,27 @@ And the following to ``style/base.css``: Run the following commands: -:: +.. code-block:: shell pip install -e . - pip install jupyter-packaging jupyter labextension develop . --overwrite jupyter lab Open a notebook and observe the new "Header" widget. - -The *ipywidgets* third party extension +The *ipywidgets* third party-extension ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This discussion will be a bit confusing since we've been using the term *widget* to refer to *lumino widgets*. In the discussion below, -*ipython widgets* will be referred to as *ipywidgets*. There is no -intrinsic relation between *lumino widgets* and *ipython widgets*. +*Jupyter interactive widgets* will be referred to as *ipywidgets*. There is no +intrinsic relation between *lumino widgets* and *Jupyter interactive widgets*. The *ipywidgets* extension registers a factory for a notebook *widget* extension using the `Document -Registry <../api/classes/docregistry.documentregistry-1.html>`__. +Registry <../api/classes/docregistry.DocumentRegistry-1.html>`__. The ``createNew()`` function is called with a NotebookPanel and -`DocumentContext <../api/interfaces/docregistry.documentregistry.icontext.html>`__. +`DocumentContext <../api/interfaces/docregistry.DocumentRegistry.IContext.html>`__. The plugin then creates a ipywidget manager (which uses the context to interact the kernel and kernel's comm manager). The plugin then registers an ipywidget renderer with the notebook instance's rendermime diff --git a/docs/source/extension/ui_components.rst b/docs/source/extension/ui_components.rst index d7abb9e9d9a5..7261963d5bad 100644 --- a/docs/source/extension/ui_components.rst +++ b/docs/source/extension/ui_components.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. raw:: html + diff --git a/examples/app/webpack.config.js b/examples/app/webpack.config.js index 721e7b69891c..f5a1ed740cb7 100644 --- a/examples/app/webpack.config.js +++ b/examples/app/webpack.config.js @@ -3,19 +3,13 @@ const data = require('./package.json'); const webpack = require('webpack'); const Build = require('@jupyterlab/builder').Build; -const crypto = require('crypto'); - -// Workaround for loaders using "md4" by default, which is not supported in FIPS-compliant OpenSSL -const cryptoOrigCreateHash = crypto.createHash; -crypto.createHash = algorithm => - cryptoOrigCreateHash(algorithm == 'md4' ? 'sha256' : algorithm); +const miniSVGDataURI = require('mini-svg-data-uri'); // Generate webpack config to copy extension assets to the build directory, // such as setting schema files, theme assets, etc. const extensionAssetConfig = Build.ensureAssets({ packageNames: data.jupyterlab.extensions, - output: './build', - hashFunction: 'sha256' + output: './build' }); module.exports = [ @@ -31,30 +25,30 @@ module.exports = [ module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - { test: /\.html$/, use: 'file-loader' }, - { test: /\.md$/, use: 'raw-loader' }, - { test: /\.(jpg|png|gif)$/, use: 'file-loader' }, - { test: /\.js.map$/, use: 'file-loader' }, + { test: /\.html$/, type: 'asset/resource' }, + { test: /\.md$/, type: 'asset/source' }, + { test: /\.(jpg|png|gif)$/, type: 'asset/resource' }, + { test: /\.js.map$/, type: 'asset/resource' }, { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/font-woff' + type: 'asset' }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/font-woff' + type: 'asset' }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/octet-stream' + type: 'asset' }, - { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, use: 'file-loader' }, + { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, type: 'asset/resource' }, { // In .css files, svg is loaded as a data URI. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.css$/, - use: { - loader: 'svg-url-loader', - options: { encoding: 'none', limit: 10000 } + type: 'asset/inline', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) } }, { @@ -62,18 +56,14 @@ module.exports = [ // must be loaded as a raw string instead of data URIs. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.js$/, - use: { - loader: 'raw-loader' - } + type: 'asset/source' } ] }, plugins: [ new webpack.DefinePlugin({ - // Needed for Blueprint. See https://github.com/palantir/blueprint/issues/4393 - 'process.env': '{}', // Needed for various packages using cwd(), like the path polyfill - process: { cwd: () => '/' } + process: { cwd: () => '/', env: {} } }) ] } diff --git a/examples/cell/README.md b/examples/cell/README.md new file mode 100644 index 000000000000..87fe5abe6c4e --- /dev/null +++ b/examples/cell/README.md @@ -0,0 +1,6 @@ +# Code cell example + +This example demonstrates how to create an application allowing the user +to interact with a single code cell. + +![preview](./example.spec.ts-snapshots/example-linux.png) diff --git a/examples/cell/example.spec.ts-snapshots/example-linux.png b/examples/cell/example.spec.ts-snapshots/example-linux.png new file mode 100644 index 000000000000..949525fed9f1 Binary files /dev/null and b/examples/cell/example.spec.ts-snapshots/example-linux.png differ diff --git a/examples/cell/main.py b/examples/cell/main.py index 89b9fe2c88fd..48194453d566 100644 --- a/examples/cell/main.py +++ b/examples/cell/main.py @@ -15,10 +15,7 @@ import os from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, -) +from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin, ExtensionHandlerMixin from jupyter_server.utils import url_path_join as ujoin from jupyterlab_server import LabServerApp @@ -57,7 +54,6 @@ def get(self): class ExampleApp(LabServerApp): - extension_url = "/example" default_url = "/example" app_url = "/example" diff --git a/examples/cell/package.json b/examples/cell/package.json index 6d584f96bd61..a3eaabaebf1c 100644 --- a/examples/cell/package.json +++ b/examples/cell/package.json @@ -1,39 +1,35 @@ { "name": "@jupyterlab/example-cell", - "version": "3.6.6", + "version": "4.0.8", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/cells": "^3.6.6", - "@jupyterlab/codemirror": "^3.6.6", - "@jupyterlab/completer": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/theme-light-extension": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/commands": "^1.19.0", - "@lumino/widgets": "^1.37.2", - "es6-promise": "~4.2.8" + "@jupyter/ydoc": "^1.0.2", + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/cells": "^4.0.8", + "@jupyterlab/codemirror": "^4.0.8", + "@jupyterlab/completer": "^4.0.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/theme-light-extension": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/commands": "^2.1.3", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", - "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", + "css-loader": "^6.7.1", + "mini-css-extract-plugin": "^2.7.0", + "mini-svg-data-uri": "^1.4.4", "rimraf": "~3.0.0", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "typescript": "~4.1.3", - "url-loader": "~4.1.0", - "watch": "~1.0.2", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0", + "style-loader": "~3.3.1", + "typescript": "~5.0.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/cell/src/index.ts b/examples/cell/src/index.ts old mode 100755 new mode 100644 index d05db0a392ad..2d138f81bae9 --- a/examples/cell/src/index.ts +++ b/examples/cell/src/index.ts @@ -13,17 +13,35 @@ import '@jupyterlab/theme-light-extension/style/theme.css'; import '@jupyterlab/completer/style/index.css'; import '../index.css'; -import { SessionContext, Toolbar } from '@jupyterlab/apputils'; +import { + Toolbar as AppToolbar, + SessionContext, + SessionContextDialogs +} from '@jupyterlab/apputils'; +import { + refreshIcon, + stopIcon, + Toolbar, + ToolbarButton +} from '@jupyterlab/ui-components'; -import { CodeCell, CodeCellModel } from '@jupyterlab/cells'; +import { Cell, CodeCell, CodeCellModel } from '@jupyterlab/cells'; -import { CodeMirrorMimeTypeService } from '@jupyterlab/codemirror'; +import { + CodeMirrorEditorFactory, + CodeMirrorMimeTypeService, + EditorExtensionRegistry, + EditorLanguageRegistry, + EditorThemeRegistry, + ybinding +} from '@jupyterlab/codemirror'; import { Completer, CompleterModel, CompletionHandler, - KernelConnector + KernelCompleterProvider, + ProviderReconciliator } from '@jupyterlab/completer'; import { @@ -37,6 +55,8 @@ import { SessionManager } from '@jupyterlab/services'; +import { IYText } from '@jupyter/ydoc'; + import { CommandRegistry } from '@lumino/commands'; import { BoxPanel, Widget } from '@lumino/widgets'; @@ -50,7 +70,46 @@ function main(): void { specsManager, name: 'Example' }); - const mimeService = new CodeMirrorMimeTypeService(); + const editorExtensions = () => { + const themes = new EditorThemeRegistry(); + EditorThemeRegistry.getDefaultThemes().forEach(theme => { + themes.addTheme(theme); + }); + const registry = new EditorExtensionRegistry(); + + EditorExtensionRegistry.getDefaultExtensions({ themes }).forEach( + extensionFactory => { + registry.addExtension(extensionFactory); + } + ); + registry.addExtension({ + name: 'shared-model-binding', + factory: options => { + const sharedModel = options.model.sharedModel as IYText; + return EditorExtensionRegistry.createImmutableExtension( + ybinding({ + ytext: sharedModel.ysource, + undoManager: sharedModel.undoManager ?? undefined + }) + ); + } + }); + return registry; + }; + const languages = new EditorLanguageRegistry(); + EditorLanguageRegistry.getDefaultLanguages() + .filter(language => + ['ipython', 'julia', 'python'].includes(language.name.toLowerCase()) + ) + .forEach(language => { + languages.addLanguage(language); + }); + + const factoryService = new CodeMirrorEditorFactory({ + extensions: editorExtensions(), + languages + }); + const mimeService = new CodeMirrorMimeTypeService(languages); // Initialize the command registry with the bindings. const commands = new CommandRegistry(); @@ -69,15 +128,22 @@ function main(): void { const rendermime = new RenderMimeRegistry({ initialFactories }); const cellWidget = new CodeCell({ + contentFactory: new Cell.ContentFactory({ + editorFactory: factoryService.newInlineEditor.bind(factoryService) + }), rendermime, - model: new CodeCellModel({}) + model: new CodeCellModel() }).initializeState(); // Handle the mimeType for the current kernel asynchronously. sessionContext.kernelChanged.connect(() => { void sessionContext.session?.kernel?.info.then(info => { const lang = info.language_info; - const mimeType = mimeService.getMimeTypeByLanguage(lang); + const mimeTypes = mimeService.getMimeTypeByLanguage(lang); + const mimeType = + Array.isArray(mimeTypes) && mimeTypes.length !== 0 + ? mimeTypes[0] + : mimeTypes; cellWidget.model.mimeType = mimeType; }); }); @@ -89,13 +155,22 @@ function main(): void { const editor = cellWidget.editor; const model = new CompleterModel(); const completer = new Completer({ editor, model }); - const connector = new KernelConnector({ session: sessionContext.session }); - const handler = new CompletionHandler({ completer, connector }); + const timeout = 1000; + const provider = new KernelCompleterProvider(); + const reconciliator = new ProviderReconciliator({ + context: { widget: cellWidget, editor, session: sessionContext.session }, + providers: [provider], + timeout: timeout + }); + const handler = new CompletionHandler({ completer, reconciliator }); //sessionContext.session?.kernel. void sessionContext.ready.then(() => { - handler.connector = new KernelConnector({ - session: sessionContext.session + const provider = new KernelCompleterProvider(); + handler.reconciliator = new ProviderReconciliator({ + context: { widget: cellWidget, editor, session: sessionContext.session }, + providers: [provider], + timeout: timeout }); }); @@ -109,10 +184,32 @@ function main(): void { // Create a toolbar for the cell. const toolbar = new Toolbar(); toolbar.addItem('spacer', Toolbar.createSpacerItem()); - toolbar.addItem('interrupt', Toolbar.createInterruptButton(sessionContext)); - toolbar.addItem('restart', Toolbar.createRestartButton(sessionContext)); - toolbar.addItem('name', Toolbar.createKernelNameItem(sessionContext)); - toolbar.addItem('status', Toolbar.createKernelStatusItem(sessionContext)); + toolbar.addItem( + 'interrupt', + new ToolbarButton({ + icon: stopIcon, + onClick: () => { + void sessionContext.session?.kernel?.interrupt(); + }, + tooltip: 'Interrupt the kernel' + }) + ); + const dialogs = new SessionContextDialogs(); + toolbar.addItem( + 'restart', + new ToolbarButton({ + icon: refreshIcon, + onClick: () => { + void dialogs.restart(sessionContext); + }, + tooltip: 'Restart the kernel' + }) + ); + toolbar.addItem( + 'name', + AppToolbar.createKernelNameItem(sessionContext, dialogs) + ); + toolbar.addItem('status', AppToolbar.createKernelStatusItem(sessionContext)); // Lay out the widgets. const panel = new BoxPanel(); diff --git a/examples/cell/templates/index.html b/examples/cell/templates/index.html index 7cdf0c57b11d..46c23e57284c 100644 --- a/examples/cell/templates/index.html +++ b/examples/cell/templates/index.html @@ -1,3 +1,8 @@ + + @@ -5,10 +10,10 @@ {# Copy so we do not modify the page_config with updates. #} {% set page_config_full = page_config.copy() %} - + {# Set a dummy variable - we just want the side effect of the update. #} {% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} - + diff --git a/examples/cell/webpack.config.js b/examples/cell/webpack.config.js index 854faadb05be..a426283ce87e 100644 --- a/examples/cell/webpack.config.js +++ b/examples/cell/webpack.config.js @@ -1,17 +1,16 @@ -const webpack = require('webpack'); -const crypto = require('crypto'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ -// Workaround for loaders using "md4" by default, which is not supported in FIPS-compliant OpenSSL -const cryptoOrigCreateHash = crypto.createHash; -crypto.createHash = algorithm => - cryptoOrigCreateHash(algorithm == 'md4' ? 'sha256' : algorithm); +const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], output: { path: __dirname + '/build', - filename: 'bundle.js', - hashFunction: 'sha256' + filename: 'bundle.js' }, bail: true, devtool: 'cheap-source-map', @@ -19,16 +18,16 @@ module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - { test: /\.html$/, use: 'file-loader' }, - { test: /\.md$/, use: 'raw-loader' }, - { test: /\.js.map$/, use: 'file-loader' }, + { test: /\.html$/, type: 'asset/resource' }, + { test: /\.md$/, type: 'asset/source' }, + { test: /\.js.map$/, type: 'asset/resource' }, { // In .css files, svg is loaded as a data URI. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.css$/, - use: { - loader: 'svg-url-loader', - options: { encoding: 'none', limit: 10000 } + type: 'asset', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) } }, { @@ -36,22 +35,18 @@ module.exports = { // must be loaded as a raw string instead of data URIs. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.js$/, - use: { - loader: 'raw-loader' - } + type: 'asset/source' }, { test: /\.(png|jpg|gif|ttf|woff|woff2|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - use: [{ loader: 'url-loader', options: { limit: 10000 } }] + type: 'asset' } ] }, plugins: [ new webpack.DefinePlugin({ - // Needed for Blueprint. See https://github.com/palantir/blueprint/issues/4393 - 'process.env': '{}', // Needed for various packages using cwd(), like the path polyfill - process: { cwd: () => '/' } + process: { cwd: () => '/', env: {} } }) ] }; diff --git a/examples/chrome-example-test.js b/examples/chrome-example-test.js deleted file mode 100644 index f094f799a7d8..000000000000 --- a/examples/chrome-example-test.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * A puppeteer test that launches an example app and makes sure - * there are no console errors or uncaught errors prior to a sentinal - * string being printed. - */ -const puppeteer = require('puppeteer'); -const URL = process.argv[2]; - -async function main() { - /* eslint-disable no-console */ - console.info('Starting Chrome Headless'); - - const browser = await puppeteer.launch({ - args: ['--no-sandbox'] - }); - const page = await browser.newPage(); - - let errored = false; - - const handleMessage = async msg => { - const text = msg.text(); - const url = msg.location().url ?? ''; - if (msg.type() === 'error' && !url.includes('/api/me')) { - errored = true; - } - console.log(msg.type(), '>>', text); - const lower = text.toLowerCase(); - if (lower === 'example started!' || lower === 'test complete!') { - await browser.close(); - if (errored) { - console.error('\n\n***\nExample test failed!\n***\n\n'); - process.exit(1); - } - console.info('Example test complete!'); - return; - } else { - if (errored) { - console.error('\n\n***\nExample test failed!\n***\n\n'); - process.exit(1); - } - } - }; - - function handleError(err) { - console.error(err); - errored = true; - } - - page.on('console', handleMessage); - page.on('error', handleError); - - console.info('Navigating to page:', URL); - await page.goto(URL); - console.info('Waiting for page to loadâ€Ļ'); - - // Wait for the local file to redirect on notebook >= 6.0. Refs: - // https://jupyter-notebook.readthedocs.io/en/stable/changelog.html?highlight=redirect - // https://stackoverflow.com/q/46948489/425458 - await page.waitForNavigation(); - - if ((await page.$('#jupyter-config-data')) === null) { - console.error('Error loading JupyterLab page:'); - console.error((await page.content()).substring(0, 1000)); - } - console.info('Page loaded'); -} - -// Stop the process if an error is raised in the async function. -process.on('unhandledRejection', up => { - if (String(up).indexOf('Target closed') === -1) { - throw up; - } -}); - -main(); diff --git a/examples/console/README.md b/examples/console/README.md new file mode 100644 index 000000000000..51ebe00c46c7 --- /dev/null +++ b/examples/console/README.md @@ -0,0 +1,5 @@ +# JupyterLab console example + +This example demonstrates how to create an application displaying a code console (similar to IPython console) and a list of commands. + +![preview](./example.spec.ts-snapshots/example-linux.png) diff --git a/examples/console/example.spec.ts-snapshots/example-linux.png b/examples/console/example.spec.ts-snapshots/example-linux.png new file mode 100644 index 000000000000..18c7302b1a3f Binary files /dev/null and b/examples/console/example.spec.ts-snapshots/example-linux.png differ diff --git a/examples/console/main.py b/examples/console/main.py index b80d3a9b5a46..fd74668d5ac3 100644 --- a/examples/console/main.py +++ b/examples/console/main.py @@ -27,7 +27,6 @@ def _jupyter_server_extension_points(): class ExampleApp(LabServerApp): - extension_url = "/example" default_url = "/example" app_url = "/example" diff --git a/examples/console/package.json b/examples/console/package.json index b78aedb82425..dfd9f9458f49 100644 --- a/examples/console/package.json +++ b/examples/console/package.json @@ -1,37 +1,32 @@ { "name": "@jupyterlab/example-console", - "version": "3.6.6", + "version": "4.0.8", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/codemirror": "^3.6.6", - "@jupyterlab/console": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/theme-light-extension": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@lumino/commands": "^1.19.0", - "@lumino/widgets": "^1.37.2", - "es6-promise": "~4.2.8" + "@jupyter/ydoc": "^1.0.2", + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/codemirror": "^4.0.8", + "@jupyterlab/console": "^4.0.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/theme-light-extension": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@lumino/commands": "^2.1.3", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { - "@types/codemirror": "^0.0.109", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", - "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", + "css-loader": "^6.7.1", + "mini-css-extract-plugin": "^2.7.0", "rimraf": "~3.0.0", - "style-loader": "~2.0.0", - "typescript": "~4.1.3", - "url-loader": "~4.1.0", - "watch": "~1.0.2", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0", + "style-loader": "~3.3.1", + "typescript": "~5.0.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/console/src/index.ts b/examples/console/src/index.ts index 58a2d9573bdf..5923526d36ea 100644 --- a/examples/console/src/index.ts +++ b/examples/console/src/index.ts @@ -18,7 +18,14 @@ import { CommandPalette, SplitPanel, Widget } from '@lumino/widgets'; import { ServiceManager } from '@jupyterlab/services'; -import { editorServices } from '@jupyterlab/codemirror'; +import { + CodeMirrorEditorFactory, + CodeMirrorMimeTypeService, + EditorExtensionRegistry, + EditorLanguageRegistry, + EditorThemeRegistry, + ybinding +} from '@jupyterlab/codemirror'; import { ConsolePanel } from '@jupyterlab/console'; @@ -33,6 +40,8 @@ import { TranslationManager } from '@jupyterlab/translation'; +import { IYText } from '@jupyter/ydoc'; + async function main(): Promise { const translator = new TranslationManager(); await translator.fetch('en'); @@ -84,14 +93,55 @@ function startApp( const rendermime = new RenderMimeRegistry({ initialFactories }); - const editorFactory = editorServices.factoryService.newInlineEditor; + const editorExtensions = () => { + const themes = new EditorThemeRegistry(); + EditorThemeRegistry.getDefaultThemes().forEach(theme => { + themes.addTheme(theme); + }); + const registry = new EditorExtensionRegistry(); + + EditorExtensionRegistry.getDefaultExtensions({ themes }).forEach( + extensionFactory => { + registry.addExtension(extensionFactory); + } + ); + registry.addExtension({ + name: 'shared-model-binding', + factory: options => { + const sharedModel = options.model.sharedModel as IYText; + return EditorExtensionRegistry.createImmutableExtension( + ybinding({ + ytext: sharedModel.ysource, + undoManager: sharedModel.undoManager ?? undefined + }) + ); + } + }); + return registry; + }; + + const languages = new EditorLanguageRegistry(); + EditorLanguageRegistry.getDefaultLanguages() + .filter(language => + ['ipython', 'julia', 'python'].includes(language.name.toLowerCase()) + ) + .forEach(language => { + languages.addLanguage(language); + }); + const factoryService = new CodeMirrorEditorFactory({ + extensions: editorExtensions(), + languages + }); + const mimeTypeService = new CodeMirrorMimeTypeService(languages); + const editorFactory = factoryService.newInlineEditor; const contentFactory = new ConsolePanel.ContentFactory({ editorFactory }); + const consolePanel = new ConsolePanel({ rendermime, manager, path, contentFactory, - mimeTypeService: editorServices.mimeTypeService + mimeTypeService }); consolePanel.title.label = trans.__('Console'); diff --git a/examples/console/templates/index.html b/examples/console/templates/index.html index 7cdf0c57b11d..46c23e57284c 100644 --- a/examples/console/templates/index.html +++ b/examples/console/templates/index.html @@ -1,3 +1,8 @@ + + @@ -5,10 +10,10 @@ {# Copy so we do not modify the page_config with updates. #} {% set page_config_full = page_config.copy() %} - + {# Set a dummy variable - we just want the side effect of the update. #} {% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} - + diff --git a/examples/console/test.ipynb b/examples/console/test.ipynb index 13e846cb456c..2862792f615d 100644 --- a/examples/console/test.ipynb +++ b/examples/console/test.ipynb @@ -35,6 +35,7 @@ ], "source": [ "import sys\n", + "\n", "print('hello world', flush=True)\n", "for i in range(3):\n", " print(i, flush=True)\n", @@ -98,6 +99,7 @@ ], "source": [ "from IPython.display import Image\n", + "\n", "Image('./jupyter.png')" ] }, @@ -134,7 +136,9 @@ ], "source": [ "from IPython.display import Latex\n", - "Latex('''The mass-energy equivalence is described by the famous equation\n", + "\n", + "Latex(\n", + " '''The mass-energy equivalence is described by the famous equation\n", " \n", "$$E=mc^2$$\n", " \n", @@ -143,7 +147,8 @@ " \n", "\\\\begin{equation}\n", "E=m\n", - "\\\\end{equation}''')" + "\\\\end{equation}'''\n", + ")" ] }, { diff --git a/examples/console/webpack.config.js b/examples/console/webpack.config.js index 854faadb05be..dc0ff125e7e8 100644 --- a/examples/console/webpack.config.js +++ b/examples/console/webpack.config.js @@ -1,17 +1,16 @@ -const webpack = require('webpack'); -const crypto = require('crypto'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ -// Workaround for loaders using "md4" by default, which is not supported in FIPS-compliant OpenSSL -const cryptoOrigCreateHash = crypto.createHash; -crypto.createHash = algorithm => - cryptoOrigCreateHash(algorithm == 'md4' ? 'sha256' : algorithm); +const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], output: { path: __dirname + '/build', - filename: 'bundle.js', - hashFunction: 'sha256' + filename: 'bundle.js' }, bail: true, devtool: 'cheap-source-map', @@ -19,16 +18,16 @@ module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - { test: /\.html$/, use: 'file-loader' }, - { test: /\.md$/, use: 'raw-loader' }, - { test: /\.js.map$/, use: 'file-loader' }, + { test: /\.html$/, type: 'asset/resource' }, + { test: /\.md$/, type: 'asset/source' }, + { test: /\.js.map$/, type: 'asset/resource' }, { // In .css files, svg is loaded as a data URI. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.css$/, - use: { - loader: 'svg-url-loader', - options: { encoding: 'none', limit: 10000 } + type: 'asset/inline', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) } }, { @@ -36,22 +35,18 @@ module.exports = { // must be loaded as a raw string instead of data URIs. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.js$/, - use: { - loader: 'raw-loader' - } + type: 'asset/source' }, { test: /\.(png|jpg|gif|ttf|woff|woff2|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - use: [{ loader: 'url-loader', options: { limit: 10000 } }] + type: 'asset' } ] }, plugins: [ new webpack.DefinePlugin({ - // Needed for Blueprint. See https://github.com/palantir/blueprint/issues/4393 - 'process.env': '{}', // Needed for various packages using cwd(), like the path polyfill - process: { cwd: () => '/' } + process: { cwd: () => '/', env: {} } }) ] }; diff --git a/examples/example.spec.ts b/examples/example.spec.ts new file mode 100644 index 000000000000..5b7a45de2ecc --- /dev/null +++ b/examples/example.spec.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { ConsoleMessage, expect, test } from '@playwright/test'; + +const URL = `${process.env['BASE_URL']}`; + +test.setTimeout(120000); + +test('should load the example', async ({ page }) => { + console.info('Navigating to page:', URL); + + let errorLogs = 0; + let testEnded: (value: string | PromiseLike) => void; + const waitForTestEnd = new Promise(resolve => { + testEnded = resolve; + }); + + const handleMessage = async (msg: ConsoleMessage) => { + const text = msg.text(); + console.log(msg.type(), '>>', text); + + if (msg.type() === 'error') { + errorLogs += 1; + } + + const lower = text.toLowerCase(); + if (lower === 'example started!' || lower === 'test complete!') { + testEnded(text); + } + }; + + page.on('console', handleMessage); + + await page.goto(URL); + + // Wait for the local file to redirect on notebook >= 6.0. Refs: + // https://jupyter-notebook.readthedocs.io/en/stable/changelog.html?highlight=redirect + // https://stackoverflow.com/q/46948489/425458 + await page.waitForURL('http://**'); + + await expect.soft(page.locator('#jupyter-config-data')).toHaveCount(1); + + await waitForTestEnd; + + if (process.env['TEST_SNAPSHOT'] === '1') { + await page.waitForLoadState('networkidle'); + await page.waitForTimeout(1000); + expect + .soft( + await page.screenshot({ + mask: [page.locator('.jp-DirListing-itemModified')] + }) + ) + .toMatchSnapshot('example.png'); + } + + expect(errorLogs).toEqual(0); +}); diff --git a/examples/example_check.py b/examples/example_check.py index 411fa9901f45..2972964f5748 100644 --- a/examples/example_check.py +++ b/examples/example_check.py @@ -1,35 +1,33 @@ -# -*- coding: utf-8 -*- +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + """ This file is mean to be called with a path to an example directory as its argument. We import the application entry point for the example -and add instrument them with a puppeteer test that makes sure +and add instrument them with a Playwright test that makes sure there are no console errors or uncaught errors prior to a sentinel string being printed. e.g. python example_check.py ./app """ import importlib.util -import logging import os import shutil -import subprocess import sys -from os import path as osp - -from jupyter_server.serverapp import ServerApp -from tornado.ioloop import IOLoop -from traitlets import Bool, Dict, Unicode +from pathlib import Path from jupyterlab.browser_check import run_async_process, run_test from jupyterlab.labapp import get_app_dir -here = osp.abspath(osp.dirname(__file__)) +here = Path(__file__).parent.resolve() +TEST_FILE = here / "example.spec.ts" +REF_SNAPSHOT = Path(TEST_FILE.with_suffix('.ts-snapshots').name) / "example-linux.png" def main(): # Load the main file and grab the example class so we can subclass - example_dir = sys.argv.pop() - mod_path = osp.abspath(osp.join(example_dir, "main.py")) + example_dir = Path(sys.argv[-1]) + mod_path = (example_dir / "main.py").resolve() spec = importlib.util.spec_from_file_location("example", mod_path) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) @@ -45,8 +43,8 @@ class App(mod.ExampleApp): serverapp_config = { "base_url": "/foo/", - "root_dir": osp.abspath(example_dir), - "preferred_dir": osp.abspath(example_dir), + "root_dir": str(example_dir.resolve()), + "preferred_dir": str(example_dir.resolve()), } ip = "127.0.0.1" @@ -59,23 +57,54 @@ def _jupyter_server_extension_points(): mod._jupyter_server_extension_points = _jupyter_server_extension_points - App.__name__ = osp.basename(example_dir).capitalize() + "Test" + App.__name__ = example_dir.name.capitalize() + "Test" App.launch_instance() async def run_browser(url): """Run the browser test and return an exit code.""" # Run the browser test and return an exit code. - target = osp.join(get_app_dir(), "example_test") - if not osp.exists(osp.join(target, "node_modules")): - if not osp.exists(target): - os.makedirs(osp.join(target)) - await run_async_process(["npm", "init", "-y"], cwd=target) - await run_async_process(["npm", "install", "puppeteer@^19"], cwd=target) + target = Path(get_app_dir()) / "example_test" + if not (target / "node_modules").exists(): + if not target.exists(): + target.mkdir(parents=True, exist_ok=True) + await run_async_process(["npm", "init", "-y"], cwd=str(target)) + await run_async_process(["npm", "install", "-D", "@playwright/test@^1"], cwd=str(target)) + await run_async_process(["npx", "playwright", "install", "chromium"], cwd=str(target)) + test_target = target / TEST_FILE.name + + # Copy test file shutil.copy( - osp.join(here, "chrome-example-test.js"), osp.join(target, "chrome-example-test.js") + str(TEST_FILE), + str(test_target), ) - await run_async_process(["node", "chrome-example-test.js", url], cwd=target) + # Copy reference snapshot + example_dir = Path(sys.argv[-1]) + snapshot = example_dir / REF_SNAPSHOT + has_snapshot = False + if snapshot.exists(): + has_snapshot = True + snapshot_target = target / REF_SNAPSHOT + snapshot_target.parent.mkdir(exist_ok=True) + shutil.copy(str(snapshot), str(snapshot_target)) + + results_target = target / "test-results" + dst = example_dir / results_target.name + # Force creation of the results folder as it may be listed in the filebrowser to avoid + # snapshots discrepancy + dst.mkdir(exist_ok=True) + + current_env = os.environ.copy() + current_env["BASE_URL"] = url + current_env["TEST_SNAPSHOT"] = '1' if has_snapshot else '0' + try: + await run_async_process(["npx", "playwright", "test"], env=current_env, cwd=str(target)) + finally: + # Copy back test-results folder to analyze snapshot error + if results_target.exists(): + if dst.exists(): + shutil.rmtree(dst) + shutil.copytree(str(results_target), str(dst)) if __name__ == "__main__": diff --git a/examples/federated/README.md b/examples/federated/README.md new file mode 100644 index 000000000000..4bff1fc3301e --- /dev/null +++ b/examples/federated/README.md @@ -0,0 +1,9 @@ +# JupyterLab federated application example + +This example demonstrates how to create a JupyterLab application remix by +combining existing core packages with custom packages combined through Webpack +module federation mechanism. + +![preview](./example.spec.ts-snapshots/example-linux.png) + +
    Pink rectangles mask transient data.
    diff --git a/examples/federated/core_package/bootstrap.js b/examples/federated/core_package/bootstrap.js index 1f8cb3a2cd30..7b2029755b18 100644 --- a/examples/federated/core_package/bootstrap.js +++ b/examples/federated/core_package/bootstrap.js @@ -3,6 +3,8 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ +/* global __webpack_init_sharing__ __webpack_share_scopes__ */ + // We copy some of the pageconfig parsing logic in @jupyterlab/coreutils // below, since this must run before any other files are loaded (including // @jupyterlab/coreutils). @@ -40,26 +42,6 @@ function getOption(name) { // eslint-disable-next-line no-undef __webpack_public_path__ = getOption('fullStaticUrl') + '/'; -// Promise.allSettled polyfill, until our supported browsers implement it -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled -if (Promise.allSettled === undefined) { - Promise.allSettled = promises => - Promise.all( - promises.map(promise => - promise.then( - value => ({ - status: 'fulfilled', - value - }), - reason => ({ - status: 'rejected', - reason - }) - ) - ) - ); -} - function loadScript(url) { return new Promise((resolve, reject) => { const newScript = document.createElement('script'); diff --git a/examples/federated/core_package/index.template.js b/examples/federated/core_package/index.template.js index 15f57373ea69..7274917eeae2 100644 --- a/examples/federated/core_package/index.template.js +++ b/examples/federated/core_package/index.template.js @@ -4,30 +4,18 @@ import { JupyterLab } from '@jupyterlab/application'; import { PageConfig } from '@jupyterlab/coreutils'; -// Promise.allSettled polyfill, until our supported browsers implement it -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled -if (Promise.allSettled === undefined) { - Promise.allSettled = promises => - Promise.all( - promises.map(promise => - promise - .then(value => ({ - status: "fulfilled", - value, - }), reason => ({ - status: "rejected", - reason, - })) - ) - ); -} - import('./style.js'); +const TO_DISABLE = [ + '@jupyterlab/lsp-extension', + '@jupyterlab/fileeditor-extension:language-server', + '@jupyterlab/notebook-extension:language-server' +]; + async function createModule(scope, module) { try { const factory = await window._JUPYTERLAB[scope].get(module); - return factory(); + return factory(); } catch(e) { console.warn(`Failed to create module: package: ${scope}; module: ${module}`); throw e; @@ -70,9 +58,14 @@ export async function main() { } }); + + function manuallyDisabled(id) { + return TO_DISABLE.includes(id) || TO_DISABLE.includes(id.split(":")[0]) + } + /** * Iterate over active plugins in an extension. - * + * * #### Notes * This also populates the disabled, deferred, and ignored arrays. */ @@ -88,7 +81,10 @@ export async function main() { let plugins = Array.isArray(exports) ? exports : [exports]; for (let plugin of plugins) { - if (PageConfig.Extension.isDisabled(plugin.id)) { + if ( + PageConfig.Extension.isDisabled(plugin.id) || + manuallyDisabled(plugin.id) + ) { disabled.push(plugin.id); continue; } diff --git a/examples/federated/core_package/package.json b/examples/federated/core_package/package.json index 8cf46ea43b06..19b3ead1ebae 100644 --- a/examples/federated/core_package/package.json +++ b/examples/federated/core_package/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/example-federated-core", - "version": "2.7.6", + "version": "3.0.8", "private": true, "scripts": { "build": "npm run clean && webpack", @@ -8,169 +8,150 @@ "watch": "npm run clean && webpack --watch" }, "resolutions": { - "@jupyterlab/application": "^3.6.0-rc.0", - "@jupyterlab/application-extension": "^3.6.0-rc.0", - "@jupyterlab/apputils": "^3.6.0-rc.0", - "@jupyterlab/apputils-extension": "^3.6.0-rc.0", - "@jupyterlab/attachments": "^3.6.0-rc.0", - "@jupyterlab/cells": "^3.6.0-rc.0", - "@jupyterlab/celltags": "^3.6.0-rc.0", - "@jupyterlab/celltags-extension": "^3.6.0-rc.0", - "@jupyterlab/codeeditor": "^3.6.0-rc.0", - "@jupyterlab/codemirror": "^3.6.0-rc.0", - "@jupyterlab/codemirror-extension": "^3.6.0-rc.0", - "@jupyterlab/collaboration": "^3.6.0-rc.0", - "@jupyterlab/collaboration-extension": "^3.6.0-rc.0", - "@jupyterlab/completer": "^3.6.0-rc.0", - "@jupyterlab/completer-extension": "^3.6.0-rc.0", - "@jupyterlab/console": "^3.6.0-rc.0", - "@jupyterlab/console-extension": "^3.6.0-rc.0", - "@jupyterlab/coreutils": "^5.6.0-rc.0", - "@jupyterlab/csvviewer": "^3.6.0-rc.0", - "@jupyterlab/csvviewer-extension": "^3.6.0-rc.0", - "@jupyterlab/debugger": "^3.6.0-rc.0", - "@jupyterlab/debugger-extension": "^3.6.0-rc.0", - "@jupyterlab/docmanager": "^3.6.0-rc.0", - "@jupyterlab/docmanager-extension": "^3.6.0-rc.0", - "@jupyterlab/docregistry": "^3.6.0-rc.0", - "@jupyterlab/documentsearch": "^3.6.0-rc.0", - "@jupyterlab/documentsearch-extension": "^3.6.0-rc.0", - "@jupyterlab/extensionmanager": "^3.6.0-rc.0", - "@jupyterlab/extensionmanager-extension": "^3.6.0-rc.0", - "@jupyterlab/filebrowser": "^3.6.0-rc.0", - "@jupyterlab/filebrowser-extension": "^3.6.0-rc.0", - "@jupyterlab/fileeditor": "^3.6.0-rc.0", - "@jupyterlab/fileeditor-extension": "^3.6.0-rc.0", - "@jupyterlab/help-extension": "^3.6.0-rc.0", - "@jupyterlab/htmlviewer": "^3.6.0-rc.0", - "@jupyterlab/htmlviewer-extension": "^3.6.0-rc.0", - "@jupyterlab/hub-extension": "^3.6.0-rc.0", - "@jupyterlab/imageviewer": "^3.6.0-rc.0", - "@jupyterlab/imageviewer-extension": "^3.6.0-rc.0", - "@jupyterlab/inspector": "^3.6.0-rc.0", - "@jupyterlab/inspector-extension": "^3.6.0-rc.0", - "@jupyterlab/javascript-extension": "^3.6.0-rc.0", - "@jupyterlab/json-extension": "^3.6.0-rc.0", - "@jupyterlab/launcher": "^3.6.0-rc.0", - "@jupyterlab/launcher-extension": "^3.6.0-rc.0", - "@jupyterlab/logconsole": "^3.6.0-rc.0", - "@jupyterlab/logconsole-extension": "^3.6.0-rc.0", - "@jupyterlab/mainmenu": "^3.6.0-rc.0", - "@jupyterlab/mainmenu-extension": "^3.6.0-rc.0", - "@jupyterlab/mathjax2": "^3.6.0-rc.0", - "@jupyterlab/mathjax2-extension": "^3.6.0-rc.0", - "@jupyterlab/metapackage": "^3.6.0-rc.0", - "@jupyterlab/nbconvert-css": "^3.6.0-rc.0", - "@jupyterlab/nbformat": "^3.6.0-rc.0", - "@jupyterlab/notebook": "^3.6.0-rc.0", - "@jupyterlab/notebook-extension": "^3.6.0-rc.0", - "@jupyterlab/observables": "^4.6.0-rc.0", - "@jupyterlab/outputarea": "^3.6.0-rc.0", - "@jupyterlab/pdf-extension": "^3.6.0-rc.0", - "@jupyterlab/property-inspector": "^3.6.0-rc.0", - "@jupyterlab/rendermime": "^3.6.0-rc.0", - "@jupyterlab/rendermime-extension": "^3.6.0-rc.0", - "@jupyterlab/rendermime-interfaces": "^3.6.0-rc.0", - "@jupyterlab/running": "^3.6.0-rc.0", - "@jupyterlab/running-extension": "^3.6.0-rc.0", - "@jupyterlab/services": "~6.0.0-alpha.15", - "@jupyterlab/settingeditor": "^3.6.0-rc.0", - "@jupyterlab/settingeditor-extension": "^3.6.0-rc.0", - "@jupyterlab/settingregistry": "^3.6.0-rc.0", - "@jupyterlab/shortcuts-extension": "^3.6.0-rc.0", - "@jupyterlab/statedb": "^3.6.0-rc.0", - "@jupyterlab/statusbar": "^3.6.0-rc.0", - "@jupyterlab/statusbar-extension": "^3.6.0-rc.0", - "@jupyterlab/theme-dark-extension": "^3.6.0-rc.0", - "@jupyterlab/theme-light-extension": "^3.6.0-rc.0", - "@jupyterlab/toc": "^5.6.0-rc.0", - "@jupyterlab/toc-extension": "^5.6.0-rc.0", - "@jupyterlab/tooltip": "^3.6.0-rc.0", - "@jupyterlab/tooltip-extension": "^3.6.0-rc.0", - "@jupyterlab/translation": "^3.6.0-rc.0", - "@jupyterlab/translation-extension": "^3.6.0-rc.0", - "@jupyterlab/ui-components": "^3.6.0-rc.0", - "@jupyterlab/ui-components-extension": "^3.6.0-rc.0", - "@jupyterlab/vdom": "^3.6.0-rc.0", - "@jupyterlab/vdom-extension": "^3.6.0-rc.0", - "@jupyterlab/vega5-extension": "^3.6.0-rc.0", - "@lumino/algorithm": "^1.9.0", - "@lumino/application": "^1.13.1", - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/domutils": "^1.8.0", - "@lumino/dragdrop": "^1.13.0", - "@lumino/messaging": "^1.10.0", - "@lumino/properties": "^1.8.0", - "@lumino/signaling": "^1.10.0", - "@lumino/virtualdom": "^1.14.0", - "@lumino/widgets": "^1.37.2", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "@jupyterlab/application": "~4.0.8", + "@jupyterlab/application-extension": "~4.0.8", + "@jupyterlab/apputils": "^4.0.0-alpha.15", + "@jupyterlab/apputils-extension": "~4.0.8", + "@jupyterlab/attachments": "^4.0.0-alpha.15", + "@jupyterlab/cells": "~4.0.0-alpha.3", + "@jupyterlab/celltags-extension": "~4.0.8", + "@jupyterlab/codeeditor": "^4.0.0-alpha.15", + "@jupyterlab/codemirror-extension": "~4.0.8", + "@jupyterlab/completer": "^4.0.0-alpha.15", + "@jupyterlab/completer-extension": "~4.0.8", + "@jupyterlab/console": "^4.0.0-alpha.15", + "@jupyterlab/console-extension": "~4.0.8", + "@jupyterlab/coreutils": "~6.0.8", + "@jupyterlab/csvviewer-extension": "~4.0.8", + "@jupyterlab/debugger": "^4.0.0-alpha.15", + "@jupyterlab/debugger-extension": "~4.0.8", + "@jupyterlab/docmanager": "^4.0.0-alpha.15", + "@jupyterlab/docmanager-extension": "~4.0.8", + "@jupyterlab/documentsearch": "^4.0.0-alpha.15", + "@jupyterlab/documentsearch-extension": "~4.0.8", + "@jupyterlab/extensionmanager": "^4.0.0-alpha.15", + "@jupyterlab/extensionmanager-extension": "~4.0.8", + "@jupyterlab/filebrowser": "^4.0.0-alpha.15", + "@jupyterlab/filebrowser-extension": "~4.0.8", + "@jupyterlab/fileeditor": "^4.0.0-alpha.15", + "@jupyterlab/fileeditor-extension": "~4.0.8", + "@jupyterlab/help-extension": "~4.0.8", + "@jupyterlab/htmlviewer-extension": "~4.0.8", + "@jupyterlab/hub-extension": "~4.0.8", + "@jupyterlab/imageviewer": "^4.0.0-alpha.15", + "@jupyterlab/imageviewer-extension": "~4.0.8", + "@jupyterlab/inspector": "^4.0.0-alpha.15", + "@jupyterlab/inspector-extension": "~4.0.8", + "@jupyterlab/javascript-extension": "~4.0.8", + "@jupyterlab/json-extension": "~4.0.8", + "@jupyterlab/launcher": "^4.0.0-alpha.15", + "@jupyterlab/launcher-extension": "~4.0.8", + "@jupyterlab/logconsole": "^4.0.0-alpha.15", + "@jupyterlab/logconsole-extension": "~4.0.8", + "@jupyterlab/lsp": "^4.0.0-alpha.15", + "@jupyterlab/lsp-extension": "~4.0.8", + "@jupyterlab/mainmenu": "^4.0.0-alpha.15", + "@jupyterlab/mainmenu-extension": "~4.0.8", + "@jupyterlab/markedparser-extension": "~4.0.0-alpha.15", + "@jupyterlab/mathjax-extension": "~4.0.8", + "@jupyterlab/metadataform": "^4.0.0-alpha.15", + "@jupyterlab/metadataform-extension": "~4.0.8", + "@jupyterlab/notebook": "^4.0.0-alpha.15", + "@jupyterlab/notebook-extension": "~4.0.8", + "@jupyterlab/pdf-extension": "~4.0.8", + "@jupyterlab/rendermime": "^4.0.0-alpha.15", + "@jupyterlab/rendermime-extension": "~4.0.8", + "@jupyterlab/rendermime-interfaces": "^3.8.0-alpha.9", + "@jupyterlab/services": "^7.0.0-alpha.15", + "@jupyterlab/settingeditor": "^4.0.0-alpha.15", + "@jupyterlab/settingeditor-extension": "~4.0.8", + "@jupyterlab/settingregistry": "^4.0.0-alpha.15", + "@jupyterlab/shortcuts-extension": "~4.0.8", + "@jupyterlab/statedb": "^4.0.0-alpha.15", + "@jupyterlab/statusbar": "^4.0.0-alpha.15", + "@jupyterlab/statusbar-extension": "~4.0.8", + "@jupyterlab/theme-light-extension": "~4.0.8", + "@jupyterlab/toc-extension": "~6.0.8", + "@jupyterlab/tooltip": "^4.0.0-alpha.15", + "@jupyterlab/tooltip-extension": "~4.0.8", + "@jupyterlab/translation": "~4.0.8", + "@jupyterlab/translation-extension": "~4.0.8", + "@jupyterlab/ui-components": "^4.0.0-alpha.17", + "@jupyterlab/ui-components-extension": "~4.0.8", + "@jupyterlab/vega5-extension": "~4.0.8", + "@lumino/algorithm": "^2.0.0", + "@lumino/application": "^2.0.1", + "@lumino/commands": "^2.0.1", + "@lumino/coreutils": "^2.0.0", + "@lumino/disposable": "^2.0.0", + "@lumino/domutils": "^2.0.0", + "@lumino/dragdrop": "^2.0.0", + "@lumino/messaging": "^2.0.0", + "@lumino/properties": "^2.0.0", + "@lumino/signaling": "^2.0.0", + "@lumino/virtualdom": "^2.0.0", + "@lumino/widgets": "^2.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "yjs": "^13.5.40" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/application-extension": "^3.6.6", - "@jupyterlab/apputils-extension": "^3.6.6", - "@jupyterlab/celltags-extension": "^3.6.6", - "@jupyterlab/codemirror-extension": "^3.6.6", - "@jupyterlab/collaboration-extension": "^3.6.6", - "@jupyterlab/completer-extension": "^3.6.6", - "@jupyterlab/console-extension": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/csvviewer-extension": "^3.6.6", - "@jupyterlab/docmanager-extension": "^3.6.6", - "@jupyterlab/documentsearch-extension": "^3.6.6", - "@jupyterlab/extensionmanager-extension": "^3.6.6", - "@jupyterlab/filebrowser-extension": "^3.6.6", - "@jupyterlab/fileeditor-extension": "^3.6.6", - "@jupyterlab/help-extension": "^3.6.6", - "@jupyterlab/htmlviewer-extension": "^3.6.6", - "@jupyterlab/hub-extension": "^3.6.6", - "@jupyterlab/imageviewer-extension": "^3.6.6", - "@jupyterlab/inspector-extension": "^3.6.6", - "@jupyterlab/javascript-extension": "^3.6.6", - "@jupyterlab/json-extension": "^3.6.6", - "@jupyterlab/launcher-extension": "^3.6.6", - "@jupyterlab/logconsole-extension": "^3.6.6", - "@jupyterlab/mainmenu-extension": "^3.6.6", - "@jupyterlab/mathjax2-extension": "^3.6.6", - "@jupyterlab/notebook-extension": "^3.6.6", - "@jupyterlab/pdf-extension": "^3.6.6", - "@jupyterlab/rendermime-extension": "^3.6.6", - "@jupyterlab/settingeditor-extension": "^3.6.6", - "@jupyterlab/shortcuts-extension": "^3.6.6", - "@jupyterlab/statusbar-extension": "^3.6.6", - "@jupyterlab/theme-light-extension": "^3.6.6", - "@jupyterlab/toc-extension": "^5.6.6", - "@jupyterlab/tooltip-extension": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/translation-extension": "^3.6.6", - "@jupyterlab/ui-components-extension": "^3.6.6", - "@jupyterlab/vdom-extension": "^3.6.6", - "@jupyterlab/vega5-extension": "^3.6.6" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/application-extension": "^4.0.8", + "@jupyterlab/apputils-extension": "^4.0.8", + "@jupyterlab/celltags-extension": "^4.0.8", + "@jupyterlab/codemirror-extension": "^4.0.8", + "@jupyterlab/completer-extension": "^4.0.8", + "@jupyterlab/console-extension": "^4.0.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/csvviewer-extension": "^4.0.8", + "@jupyterlab/debugger-extension": "^4.0.8", + "@jupyterlab/docmanager-extension": "^4.0.8", + "@jupyterlab/documentsearch-extension": "^4.0.8", + "@jupyterlab/extensionmanager-extension": "^4.0.8", + "@jupyterlab/filebrowser-extension": "^4.0.8", + "@jupyterlab/fileeditor-extension": "^4.0.8", + "@jupyterlab/help-extension": "^4.0.8", + "@jupyterlab/htmlviewer-extension": "^4.0.8", + "@jupyterlab/hub-extension": "^4.0.8", + "@jupyterlab/imageviewer-extension": "^4.0.8", + "@jupyterlab/inspector-extension": "^4.0.8", + "@jupyterlab/javascript-extension": "^4.0.8", + "@jupyterlab/json-extension": "^4.0.8", + "@jupyterlab/launcher-extension": "^4.0.8", + "@jupyterlab/logconsole-extension": "^4.0.8", + "@jupyterlab/lsp-extension": "^4.0.8", + "@jupyterlab/mainmenu-extension": "^4.0.8", + "@jupyterlab/mathjax-extension": "^4.0.8", + "@jupyterlab/metadataform-extension": "^4.0.8", + "@jupyterlab/notebook-extension": "^4.0.8", + "@jupyterlab/pdf-extension": "^4.0.8", + "@jupyterlab/rendermime-extension": "^4.0.8", + "@jupyterlab/settingeditor-extension": "^4.0.8", + "@jupyterlab/shortcuts-extension": "^4.0.8", + "@jupyterlab/statusbar-extension": "^4.0.8", + "@jupyterlab/theme-light-extension": "^4.0.8", + "@jupyterlab/toc-extension": "^6.0.8", + "@jupyterlab/tooltip-extension": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/translation-extension": "^4.0.8", + "@jupyterlab/ui-components-extension": "^4.0.8", + "@jupyterlab/vega5-extension": "^4.0.8" }, "devDependencies": { - "@jupyterlab/builder": "^3.6.6", - "copy-webpack-plugin": "^6.0.1", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", - "fs-extra": "^9.0.1", + "@jupyterlab/builder": "^4.0.8", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.7.1", + "fs-extra": "^10.1.0", "glob": "~7.1.6", "handlebars": "^4.5.3", - "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", - "read-package-tree": "^5.3.1", + "mini-css-extract-plugin": "^2.7.0", + "mini-svg-data-uri": "^1.4.4", "rimraf": "~3.0.0", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "to-string-loader": "^1.1.6", - "url-loader": "~4.1.0", - "watch": "~1.0.2", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0", - "webpack-merge": "^5.1.2", + "style-loader": "~3.3.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-merge": "^5.8.0", "whatwg-fetch": "^3.0.0" }, "jupyterlab": { @@ -181,8 +162,8 @@ "singletonPackages": [ "@jupyterlab/application", "@jupyterlab/apputils", + "@jupyterlab/attachments", "@jupyterlab/codeeditor", - "@jupyterlab/collaboration", "@jupyterlab/completer", "@jupyterlab/console", "@jupyterlab/coreutils", @@ -196,6 +177,7 @@ "@jupyterlab/inspector", "@jupyterlab/launcher", "@jupyterlab/logconsole", + "@jupyterlab/lsp", "@jupyterlab/mainmenu", "@jupyterlab/notebook", "@jupyterlab/rendermime", @@ -206,6 +188,7 @@ "@jupyterlab/statedb", "@jupyterlab/statusbar", "@jupyterlab/tooltip", + "@jupyterlab/translation", "@jupyterlab/ui-components", "@lumino/algorithm", "@lumino/application", @@ -220,7 +203,8 @@ "@lumino/virtualdom", "@lumino/widgets", "react", - "react-dom" + "react-dom", + "yjs" ], "extensions": [ "@jupyterlab/application-extension", @@ -230,6 +214,7 @@ "@jupyterlab/completer-extension", "@jupyterlab/console-extension", "@jupyterlab/csvviewer-extension", + "@jupyterlab/debugger-extension", "@jupyterlab/docmanager-extension", "@jupyterlab/documentsearch-extension", "@jupyterlab/extensionmanager-extension", @@ -240,24 +225,25 @@ "@jupyterlab/hub-extension", "@jupyterlab/imageviewer-extension", "@jupyterlab/inspector-extension", + "@jupyterlab/javascript-extension", + "@jupyterlab/json-extension", "@jupyterlab/launcher-extension", "@jupyterlab/logconsole-extension", + "@jupyterlab/lsp-extension", "@jupyterlab/mainmenu-extension", - "@jupyterlab/mathjax2-extension", + "@jupyterlab/mathjax-extension", + "@jupyterlab/metadataform-extension", "@jupyterlab/notebook-extension", + "@jupyterlab/pdf-extension", "@jupyterlab/rendermime-extension", "@jupyterlab/settingeditor-extension", "@jupyterlab/shortcuts-extension", "@jupyterlab/statusbar-extension", "@jupyterlab/theme-light-extension", - "@jupyterlab/theme-dark-extension", + "@jupyterlab/toc-extension", "@jupyterlab/tooltip-extension", "@jupyterlab/translation-extension", "@jupyterlab/ui-components-extension", - "@jupyterlab/vdom-extension", - "@jupyterlab/javascript-extension", - "@jupyterlab/json-extension", - "@jupyterlab/pdf-extension", "@jupyterlab/vega5-extension" ] } diff --git a/examples/federated/example.cert b/examples/federated/example.cert index d42471640785..6471ecf48c9e 100644 --- a/examples/federated/example.cert +++ b/examples/federated/example.cert @@ -1 +1 @@ -{"given": "My Name", "event": "Event"} \ No newline at end of file +{"given": "My Name", "event": "Event"} diff --git a/examples/federated/example.spec.ts-snapshots/example-linux.png b/examples/federated/example.spec.ts-snapshots/example-linux.png new file mode 100644 index 000000000000..c5ffd941eaff Binary files /dev/null and b/examples/federated/example.spec.ts-snapshots/example-linux.png differ diff --git a/examples/federated/md_package/index.js b/examples/federated/md_package/index.js index 763ac29fa583..65fd9480ce01 100644 --- a/examples/federated/md_package/index.js +++ b/examples/federated/md_package/index.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. import { ILayoutRestorer } from '@jupyterlab/application'; @@ -46,7 +47,6 @@ const plugin = { * Activate the markdown viewer plugin. */ function activate(app, restorer, rendermime, settingRegistry, middleToken) { - console.log(middleToken); const { commands, docRegistry } = app; // Add the markdown renderer factory. rendermime.addFactory(markdownRendererFactory); diff --git a/examples/federated/md_package/mime.js b/examples/federated/md_package/mime.js index 7f129794a39d..c858276c0a2f 100644 --- a/examples/federated/md_package/mime.js +++ b/examples/federated/md_package/mime.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. diff --git a/examples/federated/md_package/package.json b/examples/federated/md_package/package.json index 4ee1ae83923f..6feeafb184a1 100644 --- a/examples/federated/md_package/package.json +++ b/examples/federated/md_package/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/example-federated-md", - "version": "2.7.6", + "version": "3.0.8", "private": true, "main": "./index.js", "scripts": { @@ -8,13 +8,13 @@ "clean": "rimraf ../labextensions/@jupyterlab/example-federated-md" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/example-federated-middle": "^2.7.6", - "@jupyterlab/markdownviewer-extension": "^3.6.6", - "@lumino/widgets": "^1.37.2" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/example-federated-middle": "^3.0.8", + "@jupyterlab/markdownviewer-extension": "^4.0.8", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { - "@jupyterlab/builder": "^3.6.6", + "@jupyterlab/builder": "^4.0.8", "rimraf": "~3.0.0" }, "jupyterlab": { diff --git a/examples/federated/md_package/style/index.css b/examples/federated/md_package/style/index.css index 6a25f88a0fc0..ab24a9af3098 100644 --- a/examples/federated/md_package/style/index.css +++ b/examples/federated/md_package/style/index.css @@ -5,8 +5,8 @@ .mimerenderer-certificate > .certificate { background-color: #07618b; - border-radius: 20px 20px 20px 20px; - box-shadow: 0px 5px 10px 0px; + border-radius: 20px; + box-shadow: 0 5px 10px 0; height: 250px; margin-left: 35%; margin-top: 10%; @@ -16,7 +16,7 @@ .mimerenderer-certificate > .certificate > .paper { background: #e0e0e0; - border-radius: 5px 5px 5px 5px; + border-radius: 5px; height: 200px; left: 25px; position: absolute; @@ -35,7 +35,7 @@ .mimerenderer-certificate > .certificate > .paper > .text { margin-top: 20px; - padding: 0px; + padding: 0; text-align: center; z-index: 200; } @@ -46,7 +46,7 @@ font-size: 2em; height: 20px; left: 30px; - padding: 10px 10px 10px 10px; + padding: 10px; position: absolute; top: 30px; width: 20px; diff --git a/examples/federated/middle_package/package.json b/examples/federated/middle_package/package.json index 2173491c9af4..3d8b06cafe63 100644 --- a/examples/federated/middle_package/package.json +++ b/examples/federated/middle_package/package.json @@ -1,16 +1,16 @@ { "name": "@jupyterlab/example-federated-middle", - "version": "2.7.6", + "version": "3.0.8", "private": true, "scripts": { "build": "npm run clean && build-labextension --core-path ../core_package .", "clean": "rimraf ../labextensions/@jupyterlab/example-federated-middle" }, "dependencies": { - "@lumino/coreutils": "^1.11.0" + "@lumino/coreutils": "^2.1.2" }, "devDependencies": { - "@jupyterlab/builder": "^3.6.6", + "@jupyterlab/builder": "^4.0.8", "rimraf": "~3.0.0" }, "publishConfig": { diff --git a/examples/federated/package.json b/examples/federated/package.json index 0b2be093a155..86ceac24658c 100644 --- a/examples/federated/package.json +++ b/examples/federated/package.json @@ -1,17 +1,15 @@ { "name": "@jupyterlab/example-federated", - "version": "2.7.6", + "version": "3.0.8", "private": true, "scripts": { - "build": "npm run build:core && npm run build:middle && npm run build:md && npm run build:phosphor", + "build": "npm run build:core && npm run build:middle && npm run build:md", "build:core": "cd core_package && npm run build", "build:md": "cd md_package && npm run build", "build:middle": "cd middle_package && npm run build", - "build:phosphor": "cd phosphor_package && npm run build", - "install:all": "npm run install:core && npm run install:middle && npm run install:md && npm run install:phosphor", + "install:all": "npm run install:core && npm run install:middle && npm run install:md", "install:core": "cd core_package && npm install", "install:md": "cd md_package && npm install", - "install:middle": "cd middle_package && npm install", - "install:phosphor": "cd phosphor_package && npm install" + "install:middle": "cd middle_package && npm install" } } diff --git a/examples/federated/phosphor_package/index.js b/examples/federated/phosphor_package/index.js deleted file mode 100644 index a8841957ea20..000000000000 --- a/examples/federated/phosphor_package/index.js +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { Widget } from '@phosphor/widgets'; -import { MainAreaWidget } from '@jupyterlab/apputils'; - -const plugins = [ - { - id: '@jupyterlab/example-federated-phosphor', - autoStart: true, - activate: function (app) { - const mywidget = new Widget(); - mywidget.node.textContent = 'Phosphor extension'; - mywidget.id = '@jupyterlab/example-federated-phosphor'; - mywidget.title.label = 'Phosphor extension'; - const appwidget = new MainAreaWidget({ content: mywidget }); - app.restored.then(() => { - app.shell.add(appwidget); - }); - } - } -]; - -export default plugins; diff --git a/examples/federated/phosphor_package/package.json b/examples/federated/phosphor_package/package.json deleted file mode 100644 index 2088d3127d7f..000000000000 --- a/examples/federated/phosphor_package/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@jupyterlab/example-federated-phosphor", - "version": "2.7.6", - "private": true, - "scripts": { - "build": "npm run clean && build-labextension --core-path ../core_package .", - "clean": "rimraf ../labextensions/@jupyterlab/example-federated-phosphor" - }, - "dependencies": { - "@jupyterlab/apputils": "^3.6.6", - "@phosphor/coreutils": "^1.0.0" - }, - "devDependencies": { - "@jupyterlab/builder": "^3.6.6", - "rimraf": "~3.0.0" - }, - "publishConfig": { - "access": "public" - }, - "jupyterlab": { - "extension": true, - "outputDir": "../labextensions/@jupyterlab/example-federated-phosphor" - } -} diff --git a/examples/federated/templates/index.html b/examples/federated/templates/index.html index b4c91257e23b..7d43fd0c0be5 100644 --- a/examples/federated/templates/index.html +++ b/examples/federated/templates/index.html @@ -1,3 +1,8 @@ + + diff --git a/examples/filebrowser/README.md b/examples/filebrowser/README.md new file mode 100644 index 000000000000..7f1564cbf90f --- /dev/null +++ b/examples/filebrowser/README.md @@ -0,0 +1,7 @@ +# JupyterLab filebrowser example + +This example demonstrates how to create a filebrowser application. + +![preview](./example.spec.ts-snapshots/example-linux.png) + +
    Pink rectangles mask transient data.
    diff --git a/examples/filebrowser/example.spec.ts-snapshots/example-linux.png b/examples/filebrowser/example.spec.ts-snapshots/example-linux.png new file mode 100644 index 000000000000..d09c6fa2062e Binary files /dev/null and b/examples/filebrowser/example.spec.ts-snapshots/example-linux.png differ diff --git a/examples/filebrowser/main.py b/examples/filebrowser/main.py index 67b5454c5caf..8b2ba3b5c995 100644 --- a/examples/filebrowser/main.py +++ b/examples/filebrowser/main.py @@ -27,7 +27,6 @@ def _jupyter_server_extension_points(): class ExampleApp(LabServerApp): - extension_url = "/example" default_url = "/example" app_url = "/example" diff --git a/examples/filebrowser/package.json b/examples/filebrowser/package.json index 8b5eca4ca455..3450011cfb7c 100644 --- a/examples/filebrowser/package.json +++ b/examples/filebrowser/package.json @@ -1,43 +1,36 @@ { "name": "@jupyterlab/example-filebrowser", - "version": "3.6.6", + "version": "4.0.8", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/codemirror": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/docmanager": "^3.6.6", - "@jupyterlab/docregistry": "^3.6.6", - "@jupyterlab/filebrowser": "^3.6.6", - "@jupyterlab/fileeditor": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/theme-light-extension": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/commands": "^1.19.0", - "@lumino/widgets": "^1.37.2", - "es6-promise": "~4.2.8" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/codemirror": "^4.0.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/docmanager": "^4.0.8", + "@jupyterlab/docregistry": "^4.0.8", + "@jupyterlab/filebrowser": "^4.0.8", + "@jupyterlab/fileeditor": "^4.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/theme-light-extension": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/commands": "^2.1.3", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { - "@types/codemirror": "^0.0.109", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", - "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", + "css-loader": "^6.7.1", + "mini-css-extract-plugin": "^2.7.0", + "mini-svg-data-uri": "^1.4.4", "rimraf": "~3.0.0", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "typescript": "~4.1.3", - "url-loader": "~4.1.0", - "watch": "~1.0.2", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0", + "style-loader": "~3.3.1", + "typescript": "~5.0.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/filebrowser/src/index.ts b/examples/filebrowser/src/index.ts index d27a1a1ac9e0..2c0f82ad71be 100644 --- a/examples/filebrowser/src/index.ts +++ b/examples/filebrowser/src/index.ts @@ -13,19 +13,18 @@ import '@jupyterlab/filebrowser/style/index.css'; import '@jupyterlab/theme-light-extension/style/theme.css'; import '../index.css'; -import { each } from '@lumino/algorithm'; - import { CommandRegistry } from '@lumino/commands'; import { DockPanel, Menu, SplitPanel, Widget } from '@lumino/widgets'; import { ServiceManager } from '@jupyterlab/services'; -import { Dialog, showDialog, ToolbarButton } from '@jupyterlab/apputils'; +import { Dialog, showDialog } from '@jupyterlab/apputils'; import { CodeMirrorEditorFactory, - CodeMirrorMimeTypeService + CodeMirrorMimeTypeService, + EditorLanguageRegistry } from '@jupyterlab/codemirror'; import { DocumentManager } from '@jupyterlab/docmanager'; @@ -42,7 +41,7 @@ import { TranslationManager } from '@jupyterlab/translation'; -import { addIcon } from '@jupyterlab/ui-components'; +import { addIcon, ToolbarButton } from '@jupyterlab/ui-components'; const LANG = 'en'; @@ -79,6 +78,16 @@ function createApp( const index = widgets.indexOf(w); widgets.splice(index, 1); }); + }, + get opened() { + return { + connect: () => { + return false; + }, + disconnect: () => { + return false; + } + }; } }; @@ -88,9 +97,30 @@ function createApp( manager, opener }); + const languages = new EditorLanguageRegistry(); + EditorLanguageRegistry.getDefaultLanguages() + .filter(language => + ['ipython', 'julia', 'python'].includes(language.name.toLowerCase()) + ) + .forEach(language => { + languages.addLanguage(language); + }); + // Language for Markdown cells + languages.addLanguage({ + name: 'ipythongfm', + mime: 'text/x-ipythongfm', + load: async () => { + const m = await import('@codemirror/lang-markdown'); + return m.markdown({ + codeLanguages: (info: string) => languages.findBest(info) as any + }); + } + }); + const factoryService = new CodeMirrorEditorFactory({ languages }); + const mimeTypeService = new CodeMirrorMimeTypeService(languages); const editorServices = { - factoryService: new CodeMirrorEditorFactory(), - mimeTypeService: new CodeMirrorMimeTypeService() + factoryService, + mimeTypeService }; const wFactory = new FileEditorFactory({ editorServices, @@ -153,17 +183,17 @@ function createApp( // Add commands. commands.addCommand('file-open', { label: trans.__('Open'), - icon: 'fa fa-folder-open-o', + iconClass: 'fa fa-folder-open-o', mnemonic: 0, execute: () => { - each(fbWidget.selectedItems(), item => { + for (const item of fbWidget.selectedItems()) { docManager.openOrReveal(item.path); - }); + } } }); commands.addCommand('file-rename', { label: trans.__('Rename'), - icon: 'fa fa-edit', + iconClass: 'fa fa-edit', mnemonic: 0, execute: () => { return fbWidget.rename(); @@ -177,14 +207,14 @@ function createApp( }); commands.addCommand('file-cut', { label: trans.__('Cut'), - icon: 'fa fa-cut', + iconClass: 'fa fa-cut', execute: () => { fbWidget.cut(); } }); commands.addCommand('file-copy', { label: trans.__('Copy'), - icon: 'fa fa-copy', + iconClass: 'fa fa-copy', mnemonic: 0, execute: () => { fbWidget.copy(); @@ -192,7 +222,7 @@ function createApp( }); commands.addCommand('file-delete', { label: trans.__('Delete'), - icon: 'fa fa-remove', + iconClass: 'fa fa-remove', mnemonic: 0, execute: () => { return fbWidget.delete(); @@ -200,7 +230,7 @@ function createApp( }); commands.addCommand('file-duplicate', { label: trans.__('Duplicate'), - icon: 'fa fa-copy', + iconClass: 'fa fa-copy', mnemonic: 0, execute: () => { return fbWidget.duplicate(); @@ -208,7 +238,7 @@ function createApp( }); commands.addCommand('file-paste', { label: trans.__('Paste'), - icon: 'fa fa-paste', + iconClass: 'fa fa-paste', mnemonic: 0, execute: () => { return fbWidget.paste(); @@ -216,14 +246,14 @@ function createApp( }); commands.addCommand('file-download', { label: trans.__('Download'), - icon: 'fa fa-download', + iconClass: 'fa fa-download', execute: () => { return fbWidget.download(); } }); commands.addCommand('file-shutdown-kernel', { label: trans.__('Shut Down Kernel'), - icon: 'fa fa-stop-circle-o', + iconClass: 'fa fa-stop-circle-o', execute: () => { return fbWidget.shutdownKernels(); } diff --git a/examples/filebrowser/templates/index.html b/examples/filebrowser/templates/index.html index 7cdf0c57b11d..46c23e57284c 100644 --- a/examples/filebrowser/templates/index.html +++ b/examples/filebrowser/templates/index.html @@ -1,3 +1,8 @@ + + @@ -5,10 +10,10 @@ {# Copy so we do not modify the page_config with updates. #} {% set page_config_full = page_config.copy() %} - + {# Set a dummy variable - we just want the side effect of the update. #} {% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} - + diff --git a/examples/filebrowser/webpack.config.js b/examples/filebrowser/webpack.config.js index fd8a61a6d82a..ddcae875b187 100644 --- a/examples/filebrowser/webpack.config.js +++ b/examples/filebrowser/webpack.config.js @@ -1,17 +1,16 @@ -const webpack = require('webpack'); -const crypto = require('crypto'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ -// Workaround for loaders using "md4" by default, which is not supported in FIPS-compliant OpenSSL -const cryptoOrigCreateHash = crypto.createHash; -crypto.createHash = algorithm => - cryptoOrigCreateHash(algorithm == 'md4' ? 'sha256' : algorithm); +const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], output: { path: __dirname + '/build', - filename: 'bundle.js', - hashFunction: 'sha256' + filename: 'bundle.js' }, bail: true, devtool: 'source-map', @@ -19,16 +18,16 @@ module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - { test: /\.html$/, use: 'file-loader' }, - { test: /\.md$/, use: 'raw-loader' }, - { test: /\.js.map$/, use: 'file-loader' }, + { test: /\.html$/, type: 'asset/resource' }, + { test: /\.md$/, type: 'asset/source' }, + { test: /\.js.map$/, type: 'asset/resource' }, { // In .css files, svg is loaded as a data URI. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.css$/, - use: { - loader: 'svg-url-loader', - options: { encoding: 'none', limit: 10000 } + type: 'asset/inline', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) } }, { @@ -36,22 +35,18 @@ module.exports = { // must be loaded as a raw string instead of data URIs. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.js$/, - use: { - loader: 'raw-loader' - } + type: 'asset/source' }, { test: /\.(png|jpg|gif|ttf|woff|woff2|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - use: [{ loader: 'url-loader', options: { limit: 10000 } }] + type: 'asset' } ] }, plugins: [ new webpack.DefinePlugin({ - // Needed for Blueprint. See https://github.com/palantir/blueprint/issues/4393 - 'process.env': '{}', // Needed for various packages using cwd(), like the path polyfill - process: { cwd: () => '/' } + process: { cwd: () => '/', env: {} } }) ] }; diff --git a/examples/notebook/README.md b/examples/notebook/README.md new file mode 100644 index 000000000000..287d34ca2302 --- /dev/null +++ b/examples/notebook/README.md @@ -0,0 +1,5 @@ +# JupyterLab notebook example + +This example demonstrates how to create a single notebook application. + +![preview](./example.spec.ts-snapshots/example-linux.png) diff --git a/examples/notebook/example.spec.ts-snapshots/example-linux.png b/examples/notebook/example.spec.ts-snapshots/example-linux.png new file mode 100644 index 000000000000..8286ba49ad9b Binary files /dev/null and b/examples/notebook/example.spec.ts-snapshots/example-linux.png differ diff --git a/examples/notebook/main.py b/examples/notebook/main.py index db257db28ae9..099a13466252 100644 --- a/examples/notebook/main.py +++ b/examples/notebook/main.py @@ -15,10 +15,7 @@ import os from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, -) +from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin, ExtensionHandlerMixin from jupyter_server.utils import url_path_join as ujoin from jupyterlab_server import LabServerApp @@ -39,12 +36,6 @@ class ExampleHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterH def get(self): """Get the main page for the application's interface.""" - # Options set here can be read with PageConfig.getOption - mathjax_config = self.settings.get("mathjax_config", "TeX-AMS_HTML-full,Safe") - mathjax_url = self.settings.get( - "mathjax_url", "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js" - ) - config_data = { # Use camelCase here, since that's what the lab components expect "baseUrl": self.base_url, @@ -52,8 +43,6 @@ def get(self): "notebookPath": "test.ipynb", "fullStaticUrl": ujoin(self.base_url, "static", self.name), "frontendUrl": ujoin(self.base_url, "example/"), - "mathjaxUrl": mathjax_url, - "mathjaxConfig": mathjax_config, } return self.write( self.render_template( @@ -67,7 +56,6 @@ def get(self): class ExampleApp(LabServerApp): - extension_url = "/example" default_url = "/example" app_url = "/example" @@ -81,8 +69,6 @@ class ExampleApp(LabServerApp): user_settings_dir = os.path.join(HERE, "build", "user_settings") workspaces_dir = os.path.join(HERE, "build", "workspaces") - serverapp_config = {"jpserver_extensions": {"nbclassic": True}} - def initialize_handlers(self): """Add example handler to Lab Server's handler list.""" self.handlers.append(("/example", ExampleHandler)) diff --git a/examples/notebook/package.json b/examples/notebook/package.json index 667a2af71608..ceb2caf159e7 100644 --- a/examples/notebook/package.json +++ b/examples/notebook/package.json @@ -1,43 +1,41 @@ { "name": "@jupyterlab/example-notebook", - "version": "3.6.6", + "version": "4.0.8", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/codemirror": "^3.6.6", - "@jupyterlab/completer": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/docmanager": "^3.6.6", - "@jupyterlab/docregistry": "^3.6.6", - "@jupyterlab/documentsearch": "^3.6.6", - "@jupyterlab/mathjax2": "^3.6.6", - "@jupyterlab/notebook": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/theme-light-extension": "^3.6.6", - "@lumino/commands": "^1.19.0", - "@lumino/widgets": "^1.37.2", - "es6-promise": "~4.2.8" + "@jupyter/ydoc": "^1.0.2", + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/codemirror": "^4.0.8", + "@jupyterlab/completer": "^4.0.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/docmanager": "^4.0.8", + "@jupyterlab/docregistry": "^4.0.8", + "@jupyterlab/documentsearch": "^4.0.8", + "@jupyterlab/markedparser-extension": "^4.0.8", + "@jupyterlab/mathjax-extension": "^4.0.8", + "@jupyterlab/notebook": "^4.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/theme-light-extension": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/commands": "^2.1.3", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { - "@types/codemirror": "^0.0.109", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", - "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", + "css-loader": "^6.7.1", + "mini-css-extract-plugin": "^2.7.0", + "mini-svg-data-uri": "^1.4.4", "rimraf": "~3.0.0", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "typescript": "~4.1.3", - "url-loader": "~4.1.0", - "watch": "~1.0.2", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0", + "style-loader": "~3.3.1", + "typescript": "~5.0.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/notebook/src/commands.ts b/examples/notebook/src/commands.ts index dfca603a38db..70a763c57774 100644 --- a/examples/notebook/src/commands.ts +++ b/examples/notebook/src/commands.ts @@ -1,20 +1,42 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + /** * Set up keyboard shortcuts & commands for notebook */ -import { CommandRegistry } from '@lumino/commands'; -import { sessionContextDialogs } from '@jupyterlab/apputils'; +import { ISessionContextDialogs } from '@jupyterlab/apputils'; import { CompletionHandler } from '@jupyterlab/completer'; -import { NotebookActions, NotebookPanel } from '@jupyterlab/notebook'; import { - NotebookSearchProvider, - SearchInstance + SearchDocumentModel, + SearchDocumentView } from '@jupyterlab/documentsearch'; -import { CommandPalette } from '@lumino/widgets'; +import { + NotebookActions, + NotebookPanel, + NotebookSearchProvider +} from '@jupyterlab/notebook'; +import { nullTranslator } from '@jupyterlab/translation'; +import { + addIcon, + copyIcon, + cutIcon, + deleteIcon, + fastForwardIcon, + pasteIcon, + refreshIcon, + runIcon, + saveIcon, + stopIcon +} from '@jupyterlab/ui-components'; +import { CommandRegistry } from '@lumino/commands'; +import { CommandPalette, Widget } from '@lumino/widgets'; /** * The map of command ids used by the notebook. */ -const cmdIds = { +export const COMMAND_IDS = { invoke: 'completer:invoke', select: 'completer:select', invokeNotebook: 'completer:invoke-notebook', @@ -40,309 +62,408 @@ const cmdIds = { split: 'notebook-cells:split', commandMode: 'notebook:command-mode', undo: 'notebook-cells:undo', - redo: 'notebook-cells:redo' + redo: 'notebook-cells:redo', + insert: 'notebook-cells:insert', + cut: 'notebook-cells:cut', + copy: 'notebook-cells:copy', + paste: 'notebook-cells:paste', + restartAndRun: 'notebook:restart-and-run' }; -export const SetupCommands = ( +export const setupCommands = ( commands: CommandRegistry, palette: CommandPalette, nbWidget: NotebookPanel, - handler: CompletionHandler -) => { + handler: CompletionHandler, + sessionContextDialogs: ISessionContextDialogs +): void => { // Add commands. - commands.addCommand(cmdIds.invoke, { + commands.addCommand(COMMAND_IDS.invoke, { label: 'Completer: Invoke', execute: () => handler.invoke() }); - commands.addCommand(cmdIds.select, { + commands.addCommand(COMMAND_IDS.select, { label: 'Completer: Select', execute: () => handler.completer.selectActive() }); - commands.addCommand(cmdIds.invokeNotebook, { + commands.addCommand(COMMAND_IDS.invokeNotebook, { label: 'Invoke Notebook', execute: () => { if (nbWidget.content.activeCell?.model.type === 'code') { - return commands.execute(cmdIds.invoke); + return commands.execute(COMMAND_IDS.invoke); } } }); - commands.addCommand(cmdIds.selectNotebook, { + commands.addCommand(COMMAND_IDS.selectNotebook, { label: 'Select Notebook', execute: () => { if (nbWidget.content.activeCell?.model.type === 'code') { - return commands.execute(cmdIds.select); + return commands.execute(COMMAND_IDS.select); } } }); - commands.addCommand(cmdIds.save, { - label: 'Save', + commands.addCommand(COMMAND_IDS.save, { + label: args => (args.toolbar ? '' : 'Save'), + caption: 'Save', + icon: args => (args.toolbar ? saveIcon : undefined), execute: () => nbWidget.context.save() }); - let searchInstance: SearchInstance | undefined; - commands.addCommand(cmdIds.startSearch, { + let searchInstance: SearchDocumentView | undefined; + commands.addCommand(COMMAND_IDS.startSearch, { label: 'Findâ€Ļ', execute: () => { - if (searchInstance) { - searchInstance.focusInput(); - return; + if (!searchInstance) { + const provider = new NotebookSearchProvider(nbWidget, nullTranslator); + const searchModel = new SearchDocumentModel(provider, 500); + searchInstance = new SearchDocumentView(searchModel); + /** + * Activate the target widget when the search panel is closing + */ + searchInstance.closed.connect(() => { + if (!nbWidget.isDisposed) { + nbWidget.activate(); + } + }); + + searchInstance.disposed.connect(() => { + if (!nbWidget.isDisposed) { + nbWidget.activate(); + } + // find next and previous are now disabled + commands.notifyCommandChanged(COMMAND_IDS.startSearch); + }); + + /** + * Dispose resources when the widget is disposed. + */ + nbWidget.disposed.connect(() => { + searchInstance?.dispose(); + searchModel.dispose(); + provider.dispose(); + }); } - const provider = new NotebookSearchProvider(); - searchInstance = new SearchInstance(nbWidget, provider); - searchInstance.disposed.connect(() => { - searchInstance = undefined; - // find next and previous are now not enabled - commands.notifyCommandChanged(); - }); - // find next and previous are now enabled - commands.notifyCommandChanged(); - searchInstance.focusInput(); + + if (!searchInstance.isAttached) { + Widget.attach(searchInstance, nbWidget.node); + searchInstance.node.style.top = `${ + nbWidget.toolbar.node.getBoundingClientRect().height + + nbWidget.contentHeader.node.getBoundingClientRect().height + }px`; + + if (searchInstance.model.searchExpression) { + searchInstance.model.refresh(); + } + } + searchInstance.focusSearchInput(); } }); - commands.addCommand(cmdIds.findNext, { + commands.addCommand(COMMAND_IDS.findNext, { label: 'Find Next', isEnabled: () => !!searchInstance, execute: async () => { if (!searchInstance) { return; } - await searchInstance.provider.highlightNext(); - searchInstance.updateIndices(); + await searchInstance.model.highlightNext(); } }); - commands.addCommand(cmdIds.findPrevious, { + commands.addCommand(COMMAND_IDS.findPrevious, { label: 'Find Previous', isEnabled: () => !!searchInstance, execute: async () => { if (!searchInstance) { return; } - await searchInstance.provider.highlightPrevious(); - searchInstance.updateIndices(); + await searchInstance.model.highlightPrevious(); } }); - commands.addCommand(cmdIds.interrupt, { - label: 'Interrupt', + commands.addCommand(COMMAND_IDS.interrupt, { + label: args => (args.toolbar ? '' : 'Interrupt'), + caption: 'Interrupt the kernel', + icon: args => (args.toolbar ? stopIcon : undefined), execute: async () => nbWidget.context.sessionContext.session?.kernel?.interrupt() }); - commands.addCommand(cmdIds.restart, { - label: 'Restart Kernel', + commands.addCommand(COMMAND_IDS.restart, { + label: args => (args.toolbar ? '' : 'Restart Kernel'), + caption: 'Restart the kernel', + icon: args => (args.toolbar ? refreshIcon : undefined), execute: () => sessionContextDialogs.restart(nbWidget.context.sessionContext) }); - commands.addCommand(cmdIds.switchKernel, { + commands.addCommand(COMMAND_IDS.switchKernel, { label: 'Switch Kernel', execute: () => sessionContextDialogs.selectKernel(nbWidget.context.sessionContext) }); - commands.addCommand(cmdIds.runAndAdvance, { - label: 'Run and Advance', + commands.addCommand(COMMAND_IDS.runAndAdvance, { + label: args => (args.toolbar ? '' : 'Run and Advance'), + caption: 'Run the selected cells and advance.', + icon: args => (args.toolbar ? runIcon : undefined), execute: () => { return NotebookActions.runAndAdvance( nbWidget.content, - nbWidget.context.sessionContext + nbWidget.context.sessionContext, + sessionContextDialogs ); } }); - commands.addCommand(cmdIds.run, { + commands.addCommand(COMMAND_IDS.run, { label: 'Run', execute: () => { return NotebookActions.run( nbWidget.content, - nbWidget.context.sessionContext + nbWidget.context.sessionContext, + sessionContextDialogs ); } }); - commands.addCommand(cmdIds.editMode, { + commands.addCommand(COMMAND_IDS.editMode, { label: 'Edit Mode', execute: () => { nbWidget.content.mode = 'edit'; } }); - commands.addCommand(cmdIds.commandMode, { + commands.addCommand(COMMAND_IDS.commandMode, { label: 'Command Mode', execute: () => { nbWidget.content.mode = 'command'; } }); - commands.addCommand(cmdIds.selectBelow, { + commands.addCommand(COMMAND_IDS.selectBelow, { label: 'Select Below', execute: () => NotebookActions.selectBelow(nbWidget.content) }); - commands.addCommand(cmdIds.selectAbove, { + commands.addCommand(COMMAND_IDS.selectAbove, { label: 'Select Above', execute: () => NotebookActions.selectAbove(nbWidget.content) }); - commands.addCommand(cmdIds.extendAbove, { + commands.addCommand(COMMAND_IDS.extendAbove, { label: 'Extend Above', execute: () => NotebookActions.extendSelectionAbove(nbWidget.content) }); - commands.addCommand(cmdIds.extendTop, { + commands.addCommand(COMMAND_IDS.extendTop, { label: 'Extend to Top', execute: () => NotebookActions.extendSelectionAbove(nbWidget.content, true) }); - commands.addCommand(cmdIds.extendBelow, { + commands.addCommand(COMMAND_IDS.extendBelow, { label: 'Extend Below', execute: () => NotebookActions.extendSelectionBelow(nbWidget.content) }); - commands.addCommand(cmdIds.extendBottom, { + commands.addCommand(COMMAND_IDS.extendBottom, { label: 'Extend to Bottom', execute: () => NotebookActions.extendSelectionBelow(nbWidget.content, true) }); - commands.addCommand(cmdIds.merge, { + commands.addCommand(COMMAND_IDS.merge, { label: 'Merge Cells', execute: () => NotebookActions.mergeCells(nbWidget.content) }); - commands.addCommand(cmdIds.split, { + commands.addCommand(COMMAND_IDS.split, { label: 'Split Cell', execute: () => NotebookActions.splitCell(nbWidget.content) }); - commands.addCommand(cmdIds.undo, { + commands.addCommand(COMMAND_IDS.undo, { label: 'Undo', execute: () => NotebookActions.undo(nbWidget.content) }); - commands.addCommand(cmdIds.redo, { + commands.addCommand(COMMAND_IDS.redo, { label: 'Redo', execute: () => NotebookActions.redo(nbWidget.content) }); + commands.addCommand(COMMAND_IDS.insert, { + label: args => (args.toolbar ? '' : 'Insert a cell below'), + caption: 'Insert a cell below', + icon: args => (args.toolbar ? addIcon : undefined), + execute: () => NotebookActions.insertBelow(nbWidget.content) + }); + + commands.addCommand(COMMAND_IDS.deleteCell, { + label: args => (args.toolbar ? '' : 'Delete the selected cells'), + caption: 'Delete the selected cells', + icon: args => (args.toolbar ? deleteIcon : undefined), + execute: () => NotebookActions.deleteCells(nbWidget.content) + }); + + commands.addCommand(COMMAND_IDS.cut, { + label: args => (args.toolbar ? '' : 'Cut the selected cells'), + caption: 'Cut the selected cells', + icon: args => (args.toolbar ? cutIcon : undefined), + execute: () => NotebookActions.cut(nbWidget.content) + }); + + commands.addCommand(COMMAND_IDS.copy, { + label: args => (args.toolbar ? '' : 'Copy the selected cells'), + caption: 'Copy the selected cells', + icon: args => (args.toolbar ? copyIcon : undefined), + execute: () => NotebookActions.copy(nbWidget.content) + }); + + commands.addCommand(COMMAND_IDS.paste, { + label: args => (args.toolbar ? '' : 'Paste cells from the clipboard'), + caption: 'Paste cells from the clipboard', + icon: args => (args.toolbar ? pasteIcon : undefined), + execute: () => NotebookActions.paste(nbWidget.content) + }); + + commands.addCommand(COMMAND_IDS.restartAndRun, { + label: args => + args.toolbar ? '' : 'Restart the kernel, then re-run the whole notebook', + caption: 'Restart the kernl, then re-run the whole notebook', + icon: args => (args.toolbar ? fastForwardIcon : undefined), + execute: () => { + void sessionContextDialogs + .restart(nbWidget.sessionContext) + .then(restarted => { + if (restarted) { + void NotebookActions.runAll( + nbWidget.content, + nbWidget.sessionContext, + sessionContextDialogs + ); + } + return restarted; + }); + } + }); + let category = 'Notebook Operations'; [ - cmdIds.interrupt, - cmdIds.restart, - cmdIds.editMode, - cmdIds.commandMode, - cmdIds.switchKernel, - cmdIds.startSearch, - cmdIds.findNext, - cmdIds.findPrevious + COMMAND_IDS.interrupt, + COMMAND_IDS.restart, + COMMAND_IDS.editMode, + COMMAND_IDS.commandMode, + COMMAND_IDS.switchKernel, + COMMAND_IDS.startSearch, + COMMAND_IDS.findNext, + COMMAND_IDS.findPrevious ].forEach(command => palette.addItem({ command, category })); category = 'Notebook Cell Operations'; [ - cmdIds.runAndAdvance, - cmdIds.run, - cmdIds.split, - cmdIds.merge, - cmdIds.selectAbove, - cmdIds.selectBelow, - cmdIds.extendAbove, - cmdIds.extendBelow, - cmdIds.undo, - cmdIds.redo + COMMAND_IDS.runAndAdvance, + COMMAND_IDS.run, + COMMAND_IDS.split, + COMMAND_IDS.merge, + COMMAND_IDS.selectAbove, + COMMAND_IDS.selectBelow, + COMMAND_IDS.extendAbove, + COMMAND_IDS.extendBelow, + COMMAND_IDS.undo, + COMMAND_IDS.redo ].forEach(command => palette.addItem({ command, category })); const bindings = [ { selector: '.jp-Notebook.jp-mod-editMode .jp-mod-completer-enabled', keys: ['Tab'], - command: cmdIds.invokeNotebook + command: COMMAND_IDS.invokeNotebook }, { selector: `.jp-mod-completer-active`, keys: ['Enter'], - command: cmdIds.selectNotebook + command: COMMAND_IDS.selectNotebook }, { selector: '.jp-Notebook', keys: ['Ctrl Enter'], - command: cmdIds.run + command: COMMAND_IDS.run }, { selector: '.jp-Notebook', keys: ['Shift Enter'], - command: cmdIds.runAndAdvance + command: COMMAND_IDS.runAndAdvance }, { selector: '.jp-Notebook', keys: ['Accel S'], - command: cmdIds.save + command: COMMAND_IDS.save }, { selector: '.jp-Notebook', keys: ['Accel F'], - command: cmdIds.startSearch + command: COMMAND_IDS.startSearch }, { selector: '.jp-Notebook', keys: ['Accel G'], - command: cmdIds.findNext + command: COMMAND_IDS.findNext }, { selector: '.jp-Notebook', keys: ['Accel Shift G'], - command: cmdIds.findPrevious + command: COMMAND_IDS.findPrevious }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['I', 'I'], - command: cmdIds.interrupt + command: COMMAND_IDS.interrupt }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['0', '0'], - command: cmdIds.restart + command: COMMAND_IDS.restart }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['Enter'], - command: cmdIds.editMode + command: COMMAND_IDS.editMode }, { selector: '.jp-Notebook.jp-mod-editMode', keys: ['Escape'], - command: cmdIds.commandMode + command: COMMAND_IDS.commandMode }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['Shift M'], - command: cmdIds.merge + command: COMMAND_IDS.merge }, { selector: '.jp-Notebook.jp-mod-editMode', keys: ['Ctrl Shift -'], - command: cmdIds.split + command: COMMAND_IDS.split }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['J'], - command: cmdIds.selectBelow + command: COMMAND_IDS.selectBelow }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['ArrowDown'], - command: cmdIds.selectBelow + command: COMMAND_IDS.selectBelow }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['K'], - command: cmdIds.selectAbove + command: COMMAND_IDS.selectAbove }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['ArrowUp'], - command: cmdIds.selectAbove + command: COMMAND_IDS.selectAbove }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['Shift K'], - command: cmdIds.extendAbove + command: COMMAND_IDS.extendAbove }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['Shift J'], - command: cmdIds.extendBelow + command: COMMAND_IDS.extendBelow }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['Z'], - command: cmdIds.undo + command: COMMAND_IDS.undo }, { selector: '.jp-Notebook.jp-mod-commandMode:focus', keys: ['Y'], - command: cmdIds.redo + command: COMMAND_IDS.redo } ]; bindings.map(binding => commands.addKeyBinding(binding)); diff --git a/examples/notebook/src/index.ts b/examples/notebook/src/index.ts old mode 100755 new mode 100644 index f6560900ec9f..9efbd3c93027 --- a/examples/notebook/src/index.ts +++ b/examples/notebook/src/index.ts @@ -15,37 +15,48 @@ import '@jupyterlab/notebook/style/index.css'; import '@jupyterlab/theme-light-extension/style/theme.css'; import '../index.css'; -import { CommandRegistry } from '@lumino/commands'; - -import { CommandPalette, SplitPanel, Widget } from '@lumino/widgets'; - -import { ServiceManager } from '@jupyterlab/services'; -import { MathJaxTypesetter } from '@jupyterlab/mathjax2'; - +import { IYText } from '@jupyter/ydoc'; import { - NotebookModelFactory, - NotebookPanel, - NotebookWidgetFactory -} from '@jupyterlab/notebook'; - + Toolbar as AppToolbar, + CommandToolbarButton, + SessionContextDialogs +} from '@jupyterlab/apputils'; +import { + CodeMirrorEditorFactory, + CodeMirrorMimeTypeService, + EditorExtensionRegistry, + EditorLanguageRegistry, + EditorThemeRegistry, + ybinding +} from '@jupyterlab/codemirror'; import { Completer, CompleterModel, CompletionHandler, - KernelConnector + KernelCompleterProvider, + ProviderReconciliator } from '@jupyterlab/completer'; - -import { editorServices } from '@jupyterlab/codemirror'; - import { DocumentManager } from '@jupyterlab/docmanager'; - import { DocumentRegistry } from '@jupyterlab/docregistry'; - +import { createMarkdownParser } from '@jupyterlab/markedparser-extension'; +import { MathJaxTypesetter } from '@jupyterlab/mathjax-extension'; +import { + ExecutionIndicator, + NotebookModelFactory, + NotebookPanel, + NotebookWidgetFactory, + ToolbarItems +} from '@jupyterlab/notebook'; import { standardRendererFactories as initialFactories, RenderMimeRegistry } from '@jupyterlab/rendermime'; -import { SetupCommands } from './commands'; +import { ServiceManager } from '@jupyterlab/services'; +import { Toolbar } from '@jupyterlab/ui-components'; +import { CommandRegistry } from '@lumino/commands'; +import { CommandPalette, SplitPanel, Widget } from '@lumino/widgets'; + +import { COMMAND_IDS, setupCommands } from './commands'; function main(): void { const manager = new ServiceManager(); @@ -68,17 +79,27 @@ function createApp(manager: ServiceManager.IManager): void { useCapture ); + const languages = new EditorLanguageRegistry(); + const rendermime = new RenderMimeRegistry({ initialFactories: initialFactories, - latexTypesetter: new MathJaxTypesetter({ - url: PageConfig.getOption('mathjaxUrl'), - config: PageConfig.getOption('mathjaxConfig') - }) + latexTypesetter: new MathJaxTypesetter(), + markdownParser: createMarkdownParser(languages) }); const opener = { open: (widget: Widget) => { // Do nothing for sibling widgets for now. + }, + get opened() { + return { + connect: () => { + return false; + }, + disconnect: () => { + return false; + } + }; } }; @@ -89,9 +110,96 @@ function createApp(manager: ServiceManager.IManager): void { opener }); const mFactory = new NotebookModelFactory({}); - const editorFactory = editorServices.factoryService.newInlineEditor; + const editorExtensions = () => { + const themes = new EditorThemeRegistry(); + EditorThemeRegistry.getDefaultThemes().forEach(theme => { + themes.addTheme(theme); + }); + const registry = new EditorExtensionRegistry(); + + EditorExtensionRegistry.getDefaultExtensions({ themes }).forEach( + extensionFactory => { + registry.addExtension(extensionFactory); + } + ); + registry.addExtension({ + name: 'shared-model-binding', + factory: options => { + const sharedModel = options.model.sharedModel as IYText; + return EditorExtensionRegistry.createImmutableExtension( + ybinding({ + ytext: sharedModel.ysource, + undoManager: sharedModel.undoManager ?? undefined + }) + ); + } + }); + return registry; + }; + EditorLanguageRegistry.getDefaultLanguages() + .filter(language => + ['ipython', 'julia', 'python'].includes(language.name.toLowerCase()) + ) + .forEach(language => { + languages.addLanguage(language); + }); + // Language for Markdown cells + languages.addLanguage({ + name: 'ipythongfm', + mime: 'text/x-ipythongfm', + load: async () => { + const m = await import('@codemirror/lang-markdown'); + return m.markdown({ + codeLanguages: (info: string) => languages.findBest(info) as any + }); + } + }); + const factoryService = new CodeMirrorEditorFactory({ + extensions: editorExtensions(), + languages + }); + const mimeTypeService = new CodeMirrorMimeTypeService(languages); + const editorFactory = factoryService.newInlineEditor; const contentFactory = new NotebookPanel.ContentFactory({ editorFactory }); + const sessionContextDialogs = new SessionContextDialogs(); + const toolbarFactory = (panel: NotebookPanel) => + [ + COMMAND_IDS.save, + COMMAND_IDS.insert, + COMMAND_IDS.deleteCell, + COMMAND_IDS.cut, + COMMAND_IDS.copy, + COMMAND_IDS.paste, + COMMAND_IDS.runAndAdvance, + COMMAND_IDS.interrupt, + COMMAND_IDS.restart, + COMMAND_IDS.restartAndRun + ] + .map(id => ({ + name: id, + widget: new CommandToolbarButton({ + commands, + id, + args: { toolbar: true } + }) + })) + .concat([ + { name: 'cellType', widget: ToolbarItems.createCellTypeItem(panel) }, + { name: 'spacer', widget: Toolbar.createSpacerItem() }, + { + name: 'kernelName', + widget: AppToolbar.createKernelNameItem( + panel.sessionContext, + sessionContextDialogs + ) + }, + { + name: 'executionProgress', + widget: ExecutionIndicator.createExecutionIndicatorItem(panel) + } + ]); + const wFactory = new NotebookWidgetFactory({ name: 'Notebook', modelName: 'notebook', @@ -101,7 +209,8 @@ function createApp(manager: ServiceManager.IManager): void { canStartKernel: true, rendermime, contentFactory, - mimeTypeService: editorServices.mimeTypeService + mimeTypeService, + toolbarFactory }); docRegistry.addModelFactory(mFactory); docRegistry.addWidgetFactory(wFactory); @@ -116,15 +225,24 @@ function createApp(manager: ServiceManager.IManager): void { const model = new CompleterModel(); const completer = new Completer({ editor, model }); const sessionContext = nbWidget.context.sessionContext; - const connector = new KernelConnector({ - session: sessionContext.session + const timeout = 1000; + const provider = new KernelCompleterProvider(); + const reconciliator = new ProviderReconciliator({ + context: { widget: nbWidget, editor, session: sessionContext.session }, + providers: [provider], + timeout: timeout }); - const handler = new CompletionHandler({ completer, connector }); + const handler = new CompletionHandler({ completer, reconciliator }); void sessionContext.ready.then(() => { - handler.connector = new KernelConnector({ - session: sessionContext.session + const provider = new KernelCompleterProvider(); + const reconciliator = new ProviderReconciliator({ + context: { widget: nbWidget, editor, session: sessionContext.session }, + providers: [provider], + timeout: timeout }); + + handler.reconciliator = reconciliator; }); // Set the handler's editor. @@ -156,7 +274,7 @@ function createApp(manager: ServiceManager.IManager): void { panel.update(); }); - SetupCommands(commands, palette, nbWidget, handler); + setupCommands(commands, palette, nbWidget, handler, sessionContextDialogs); console.debug('Example started!'); } diff --git a/examples/notebook/templates/index.html b/examples/notebook/templates/index.html index 7cdf0c57b11d..46c23e57284c 100644 --- a/examples/notebook/templates/index.html +++ b/examples/notebook/templates/index.html @@ -1,3 +1,8 @@ + + @@ -5,10 +10,10 @@ {# Copy so we do not modify the page_config with updates. #} {% set page_config_full = page_config.copy() %} - + {# Set a dummy variable - we just want the side effect of the update. #} {% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} - + diff --git a/examples/notebook/test.ipynb b/examples/notebook/test.ipynb index 3ecf9384c9e9..89bfd7dd1a68 100644 --- a/examples/notebook/test.ipynb +++ b/examples/notebook/test.ipynb @@ -34,6 +34,7 @@ ], "source": [ "import sys\n", + "\n", "sys.stdout.write('hello world\\n')\n", "sys.stdout.flush()\n", "for i in range(3):\n", @@ -121,7 +122,9 @@ ], "source": [ "from IPython.display import Latex\n", - "Latex('''The mass-energy equivalence is described by the famous equation\n", + "\n", + "Latex(\n", + " '''The mass-energy equivalence is described by the famous equation\n", " \n", "$$E=mc^2$$\n", " \n", @@ -130,7 +133,8 @@ " \n", "\\\\begin{equation}\n", "E=m\n", - "\\\\end{equation}''')" + "\\\\end{equation}'''\n", + ")" ] }, { diff --git a/examples/notebook/webpack.config.js b/examples/notebook/webpack.config.js index 694e6eefa3ea..a981de3464fa 100644 --- a/examples/notebook/webpack.config.js +++ b/examples/notebook/webpack.config.js @@ -1,17 +1,16 @@ -const webpack = require('webpack'); -const crypto = require('crypto'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ -// Workaround for loaders using "md4" by default, which is not supported in FIPS-compliant OpenSSL -const cryptoOrigCreateHash = crypto.createHash; -crypto.createHash = algorithm => - cryptoOrigCreateHash(algorithm == 'md4' ? 'sha256' : algorithm); +const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], output: { path: __dirname + '/build', - filename: 'bundle.js', - hashFunction: 'sha256' + filename: 'bundle.js' }, bail: true, devtool: 'cheap-source-map', @@ -19,16 +18,16 @@ module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - { test: /\.html$/, use: 'file-loader' }, - { test: /\.md$/, use: 'raw-loader' }, - { test: /\.js.map$/, use: 'file-loader' }, + { test: /\.html$/, type: 'asset/resource' }, + { test: /\.md$/, type: 'asset/source' }, + { test: /\.js.map$/, type: 'asset/resource' }, { // In .css files, svg is loaded as a data URI. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.css$/, - use: { - loader: 'svg-url-loader', - options: { encoding: 'none', limit: 10000 } + type: 'asset/inline', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) } }, { @@ -36,22 +35,18 @@ module.exports = { // must be loaded as a raw string instead of data URIs. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.js$/, - use: { - loader: 'raw-loader' - } + type: 'asset/source' }, { test: /\.(png|jpg|gif|ttf|woff|woff2|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - use: [{ loader: 'url-loader', options: { limit: 10000 } }] + type: 'asset' } ] }, plugins: [ new webpack.DefinePlugin({ - // Needed for Blueprint. See https://github.com/palantir/blueprint/issues/4393 - 'process.env': '{}', // Needed for various packages using cwd(), like the path polyfill - process: { cwd: () => '/' } + process: { cwd: () => '/', env: {} } }) ] }; diff --git a/examples/notebooks/OutputExamples.ipynb b/examples/notebooks/OutputExamples.ipynb index c4391a70e4c1..a1493b51485d 100644 --- a/examples/notebooks/OutputExamples.ipynb +++ b/examples/notebooks/OutputExamples.ipynb @@ -21,9 +21,7 @@ "outputs": [], "source": [ "from IPython.display import display\n", - "from IPython.display import (\n", - " HTML, Image, Latex, Math, Markdown, SVG\n", - ")" + "from IPython.display import HTML, Image, Latex, Math, Markdown, SVG" ] }, { @@ -118,7 +116,9 @@ } ], "source": [ - "import sys; print('this is stderr', file=sys.stderr)" + "import sys\n", + "\n", + "print('this is stderr', file=sys.stderr)" ] }, { @@ -252,12 +252,14 @@ } ], "source": [ - "md = Markdown(\"\"\"\n", + "md = Markdown(\n", + " \"\"\"\n", "### Subtitle\n", "\n", "This is some *markdown* text with math $F=ma$.\n", "\n", - "\"\"\")\n", + "\"\"\"\n", + ")\n", "md" ] }, @@ -357,13 +359,15 @@ } ], "source": [ - "maxwells = Latex(r\"\"\"\n", + "maxwells = Latex(\n", + " r\"\"\"\n", "\\begin{align}\n", "\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\ \\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n", "\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n", "\\nabla \\cdot \\vec{\\mathbf{B}} & = 0\n", "\\end{align}\n", - "\"\"\")\n", + "\"\"\"\n", + ")\n", "maxwells" ] }, @@ -384,6 +388,7 @@ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from IPython.display import set_matplotlib_formats\n", + "\n", "set_matplotlib_formats('pdf')" ] }, @@ -479,9 +484,7 @@ ], "source": [ "img2 = Image(\n", - " \"https://apod.nasa.gov/apod/image/1707/GreatWallMilkyWay_Yu_1686.jpg\",\n", - " width=100,\n", - " height=200\n", + " \"https://apod.nasa.gov/apod/image/1707/GreatWallMilkyWay_Yu_1686.jpg\", width=100, height=200\n", ")\n", "img2" ] diff --git a/examples/terminal/README.md b/examples/terminal/README.md new file mode 100644 index 000000000000..3fd8c28ae8de --- /dev/null +++ b/examples/terminal/README.md @@ -0,0 +1,5 @@ +# JupyterLab terminal example + +This example demonstrates how to create a terminal application. + +![preview](./example.spec.ts-snapshots/example-linux.png) diff --git a/examples/terminal/example.spec.ts-snapshots/example-linux.png b/examples/terminal/example.spec.ts-snapshots/example-linux.png new file mode 100644 index 000000000000..8acb75c2b2c3 Binary files /dev/null and b/examples/terminal/example.spec.ts-snapshots/example-linux.png differ diff --git a/examples/terminal/main.py b/examples/terminal/main.py index 08544889bbf5..10e5f909bfb5 100644 --- a/examples/terminal/main.py +++ b/examples/terminal/main.py @@ -15,10 +15,7 @@ import os from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, -) +from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin, ExtensionHandlerMixin from jupyter_server.utils import url_path_join as ujoin from jupyterlab_server import LabServerApp @@ -60,7 +57,6 @@ def get(self): class ExampleApp(LabServerApp): - extension_url = "/example" default_url = "/example" app_url = "/example" diff --git a/examples/terminal/package.json b/examples/terminal/package.json index 316d464b5668..7f82967b03be 100644 --- a/examples/terminal/package.json +++ b/examples/terminal/package.json @@ -1,33 +1,28 @@ { "name": "@jupyterlab/example-terminal", - "version": "3.6.6", + "version": "4.0.8", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/terminal": "^3.6.6", - "@jupyterlab/theme-light-extension": "^3.6.6", - "@lumino/widgets": "^1.37.2", - "es6-promise": "~4.2.8" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/terminal": "^4.0.8", + "@jupyterlab/theme-light-extension": "^4.0.8", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", - "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", + "css-loader": "^6.7.1", + "mini-css-extract-plugin": "^2.7.0", + "mini-svg-data-uri": "^1.4.4", "rimraf": "~3.0.0", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "typescript": "~4.1.3", - "url-loader": "~4.1.0", - "watch": "~1.0.2", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0", + "style-loader": "~3.3.1", + "typescript": "~5.0.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/terminal/templates/index.html b/examples/terminal/templates/index.html index 8ff75da99bbf..96f60a46485e 100644 --- a/examples/terminal/templates/index.html +++ b/examples/terminal/templates/index.html @@ -1,3 +1,8 @@ + + @@ -5,10 +10,10 @@ {# Copy so we do not modify the page_config with updates. #} {% set page_config_full = page_config.copy() %} - + {# Set a dummy variable - we just want the side effect of the update. #} {% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} - + diff --git a/examples/terminal/webpack.config.js b/examples/terminal/webpack.config.js index a5a12b1290aa..1cc806bcbd93 100644 --- a/examples/terminal/webpack.config.js +++ b/examples/terminal/webpack.config.js @@ -1,17 +1,16 @@ -const webpack = require('webpack'); -const crypto = require('crypto'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ -// Workaround for loaders using "md4" by default, which is not supported in FIPS-compliant OpenSSL -const cryptoOrigCreateHash = crypto.createHash; -crypto.createHash = algorithm => - cryptoOrigCreateHash(algorithm == 'md4' ? 'sha256' : algorithm); +const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], output: { path: __dirname + '/build', - filename: 'bundle.js', - hashFunction: 'sha256' + filename: 'bundle.js' }, bail: true, devtool: 'cheap-source-map', @@ -19,15 +18,15 @@ module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - { test: /\.html$/, use: 'file-loader' }, - { test: /\.md$/, use: 'raw-loader' }, + { test: /\.html$/, type: 'asset/resource' }, + { test: /\.md$/, type: 'asset/source' }, { // In .css files, svg is loaded as a data URI. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.css$/, - use: { - loader: 'svg-url-loader', - options: { encoding: 'none', limit: 10000 } + type: 'asset', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) } }, { @@ -35,22 +34,18 @@ module.exports = { // must be loaded as a raw string instead of data URIs. test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.js$/, - use: { - loader: 'raw-loader' - } + type: 'asset/source' }, { test: /\.(png|jpg|gif|ttf|woff|woff2|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - use: [{ loader: 'url-loader', options: { limit: 10000 } }] + type: 'asset' } ] }, plugins: [ new webpack.DefinePlugin({ - // Needed for Blueprint. See https://github.com/palantir/blueprint/issues/4393 - 'process.env': '{}', // Needed for various packages using cwd(), like the path polyfill - process: { cwd: () => '/' } + process: { cwd: () => '/', env: {} } }) ] }; diff --git a/examples/test_examples.py b/examples/test_examples.py index 12eeb977c096..35748ee3189d 100644 --- a/examples/test_examples.py +++ b/examples/test_examples.py @@ -1,10 +1,12 @@ -# -*- coding: utf-8 -*- +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + """ This file is meant to be used to test all of the example here and and in ../packages/services/examples. We import each of the applications -and add instrument them with a puppeteer test that makes sure +and add instrument them with a Playwright test that makes sure there are no console errors or uncaught errors prior to a sentinel -string being printed (see chrome-example-test.js for the sentinel strings +string being printed (see test/example.spec.ts for the sentinel strings checked before the browser.close() call). """ import argparse @@ -20,7 +22,7 @@ def header(path): test_name = osp.basename(path) print( - "\n".join(("\n", "*" * 40, "Starting %s test in %s" % (test_name, path), "*" * 40)), + "\n".join(("\n", "*" * 40, f"Starting {test_name} test in {path}", "*" * 40)), flush=True, ) @@ -33,26 +35,33 @@ def main(): paths = [i for i in glob.glob("%s/*" % here) if osp.isdir(i)] services_dir = osp.abspath(osp.join(here, "../packages/services/examples")) - paths += [i for i in glob.glob("%s/*" % services_dir)] + paths += list(glob.glob("%s/*" % services_dir)) if args.testPath: paths = [p for p in paths if args.testPath in p] print("Testing %s" % paths) - count = 0 + failed = [] for path in sorted(paths): - if osp.basename(path) == "node": - with tempfile.TemporaryDirectory() as cwd: - header(path) - runner = osp.join(path, "main.py") - subprocess.check_call([sys.executable, runner], cwd=cwd) - count += 1 - elif osp.exists(osp.join(path, "main.py")): - with tempfile.TemporaryDirectory() as cwd: - header(path) - runner = osp.join(here, "example_check.py") - subprocess.check_call([sys.executable, runner, path], cwd=cwd) - count += 1 + try: + if osp.basename(path) == "node": + with tempfile.TemporaryDirectory() as cwd: + header(path) + runner = osp.join(path, "main.py") + subprocess.check_call([sys.executable, runner], cwd=cwd) # noqa S603 + count += 1 + elif osp.exists(osp.join(path, "main.py")): + with tempfile.TemporaryDirectory() as cwd: + header(path) + runner = osp.join(here, "example_check.py") + subprocess.check_call([sys.executable, runner, path], cwd=cwd) # noqa S603 + count += 1 + except subprocess.CalledProcessError: + failed.append(path) + + if failed: + msg = "The following examples failed:\n-{}".format("\n-".join(failed)) + raise AssertionError(msg) print("\n\n%s tests complete!" % count) diff --git a/examples/vdom/typing_slimes.gif b/examples/vdom/typing_slimes.gif deleted file mode 100644 index 710f464da72a..000000000000 Binary files a/examples/vdom/typing_slimes.gif and /dev/null differ diff --git a/examples/vdom/vdom-extension.vdom.json b/examples/vdom/vdom-extension.vdom.json deleted file mode 100644 index e60ee4989e83..000000000000 --- a/examples/vdom/vdom-extension.vdom.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "tagName": "div", - "attributes": {}, - "children": [ - { - "tagName": "h1", - "attributes": {}, - "children": "Our Incredibly Declarative Example", - "key": 0 - }, - { - "tagName": "p", - "attributes": {}, - "children": [ - "Can you believe we wrote this ", - { - "tagName": "b", - "attributes": {}, - "children": "in Python", - "key": 1 - }, - "?" - ], - "key": 1 - }, - { - "tagName": "img", - "attributes": { - "src": "https://media.giphy.com/media/xUPGcguWZHRC2HyBRS/giphy.gif" - }, - "key": 2 - }, - { - "tagName": "p", - "attributes": {}, - "children": [ - "What will ", - { - "tagName": "b", - "attributes": {}, - "children": "you", - "key": 1 - }, - " create next?" - ], - "key": 3 - } - ] -} diff --git a/examples/vdom/vdom.ipynb b/examples/vdom/vdom.ipynb deleted file mode 100644 index 1277a3992f73..000000000000 --- a/examples/vdom/vdom.ipynb +++ /dev/null @@ -1,115 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Render VDOM `json` in Python" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import display\n", - "\n", - "def VDOM(data={}):\n", - " bundle = {}\n", - " bundle['application/vdom.v1+json'] = data\n", - " display(bundle, raw=True)\n", - "\n", - "VDOM({\n", - " 'tagName': 'div',\n", - " 'attributes': {},\n", - " 'children': [{\n", - " 'tagName': 'h1',\n", - " 'attributes': {},\n", - " 'children': 'Our Incredibly Declarative Example',\n", - " 'key': 0\n", - " }, {\n", - " 'tagName': 'p',\n", - " 'attributes': {},\n", - " 'children': ['Can you believe we wrote this ', {\n", - " 'tagName': 'b',\n", - " 'attributes': {},\n", - " 'children': 'in Python',\n", - " 'key': 1\n", - " }, '?'],\n", - " 'key': 1\n", - " }, {\n", - " 'tagName': 'img',\n", - " 'attributes': {\n", - " 'src': 'https://media.giphy.com/media/xUPGcguWZHRC2HyBRS/giphy.gif'\n", - " },\n", - " 'key': 2\n", - " }, {\n", - " 'tagName': 'p',\n", - " 'attributes': {},\n", - " 'children': ['What will ', {\n", - " 'tagName': 'b',\n", - " 'attributes': {},\n", - " 'children': 'you',\n", - " 'key': 1\n", - " }, ' create next?'],\n", - " 'key': 3\n", - " }]\n", - "})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Render VDOM using the `vdom` Python package\n", - "\n", - "May need to first run `pip install vdom`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from vdom import h1, p, img, div, b\n", - "\n", - "div(\n", - " h1('Our Incredibly Declarative Example'),\n", - " p('Can you believe we wrote this ', b('in Python'), '?'),\n", - " img(src=\"https://media.giphy.com/media/xUPGcguWZHRC2HyBRS/giphy.gif\"),\n", - " p('What will ', b('you'), ' create next?'),\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/vega/vega-extension.ipynb b/examples/vega/vega-extension.ipynb index 5cc5c965ec6b..031266a8816c 100644 --- a/examples/vega/vega-extension.ipynb +++ b/examples/vega/vega-extension.ipynb @@ -19,11 +19,13 @@ "from IPython.display import display\n", "import pandas as pd\n", "\n", + "\n", "def Vega(spec):\n", " bundle = {}\n", " bundle['application/vnd.vega.v5+json'] = spec\n", " display(bundle, raw=True)\n", "\n", + "\n", "def VegaLite(spec):\n", " bundle = {}\n", " bundle['application/vnd.vegalite.v4+json'] = spec\n", @@ -225,101 +227,88 @@ } ], "source": [ - "Vega({\n", - " \"$schema\": \"https://vega.github.io/schema/vega/v5.0.json\",\n", - " \"width\": 400,\n", - " \"height\": 200,\n", - " \"padding\": 5,\n", - "\n", - " \"data\": [\n", - " {\n", - " \"name\": \"table\",\n", - " \"values\": [\n", - " {\"category\": \"A\", \"amount\": 28},\n", - " {\"category\": \"B\", \"amount\": 55},\n", - " {\"category\": \"C\", \"amount\": 43},\n", - " {\"category\": \"D\", \"amount\": 91},\n", - " {\"category\": \"E\", \"amount\": 81},\n", - " {\"category\": \"F\", \"amount\": 53},\n", - " {\"category\": \"G\", \"amount\": 19},\n", - " {\"category\": \"H\", \"amount\": 87}\n", - " ]\n", - " }\n", - " ],\n", - "\n", - " \"signals\": [\n", - " {\n", - " \"name\": \"tooltip\",\n", - " \"value\": {},\n", - " \"on\": [\n", - " {\"events\": \"rect:mouseover\", \"update\": \"datum\"},\n", - " {\"events\": \"rect:mouseout\", \"update\": \"{}\"}\n", - " ]\n", - " }\n", - " ],\n", - "\n", - " \"scales\": [\n", - " {\n", - " \"name\": \"xscale\",\n", - " \"type\": \"band\",\n", - " \"domain\": {\"data\": \"table\", \"field\": \"category\"},\n", - " \"range\": \"width\",\n", - " \"padding\": 0.05,\n", - " \"round\": True\n", - " },\n", - " {\n", - " \"name\": \"yscale\",\n", - " \"domain\": {\"data\": \"table\", \"field\": \"amount\"},\n", - " \"nice\": True,\n", - " \"range\": \"height\"\n", - " }\n", - " ],\n", - "\n", - " \"axes\": [\n", - " { \"orient\": \"bottom\", \"scale\": \"xscale\" },\n", - " { \"orient\": \"left\", \"scale\": \"yscale\" }\n", - " ],\n", - "\n", - " \"marks\": [\n", - " {\n", - " \"type\": \"rect\",\n", - " \"from\": {\"data\":\"table\"},\n", - " \"encode\": {\n", - " \"enter\": {\n", - " \"x\": {\"scale\": \"xscale\", \"field\": \"category\"},\n", - " \"width\": {\"scale\": \"xscale\", \"band\": 1},\n", - " \"y\": {\"scale\": \"yscale\", \"field\": \"amount\"},\n", - " \"y2\": {\"scale\": \"yscale\", \"value\": 0}\n", - " },\n", - " \"update\": {\n", - " \"fill\": {\"value\": \"steelblue\"}\n", - " },\n", - " \"hover\": {\n", - " \"fill\": {\"value\": \"red\"}\n", - " }\n", - " }\n", - " },\n", + "Vega(\n", " {\n", - " \"type\": \"text\",\n", - " \"encode\": {\n", - " \"enter\": {\n", - " \"align\": {\"value\": \"center\"},\n", - " \"baseline\": {\"value\": \"bottom\"},\n", - " \"fill\": {\"value\": \"#333\"}\n", - " },\n", - " \"update\": {\n", - " \"x\": {\"scale\": \"xscale\", \"signal\": \"tooltip.category\", \"band\": 0.5},\n", - " \"y\": {\"scale\": \"yscale\", \"signal\": \"tooltip.amount\", \"offset\": -2},\n", - " \"text\": {\"signal\": \"tooltip.amount\"},\n", - " \"fillOpacity\": [\n", - " {\"test\": \"datum === tooltip\", \"value\": 0},\n", - " {\"value\": 1}\n", - " ]\n", - " }\n", - " }\n", + " \"$schema\": \"https://vega.github.io/schema/vega/v5.0.json\",\n", + " \"width\": 400,\n", + " \"height\": 200,\n", + " \"padding\": 5,\n", + " \"data\": [\n", + " {\n", + " \"name\": \"table\",\n", + " \"values\": [\n", + " {\"category\": \"A\", \"amount\": 28},\n", + " {\"category\": \"B\", \"amount\": 55},\n", + " {\"category\": \"C\", \"amount\": 43},\n", + " {\"category\": \"D\", \"amount\": 91},\n", + " {\"category\": \"E\", \"amount\": 81},\n", + " {\"category\": \"F\", \"amount\": 53},\n", + " {\"category\": \"G\", \"amount\": 19},\n", + " {\"category\": \"H\", \"amount\": 87},\n", + " ],\n", + " }\n", + " ],\n", + " \"signals\": [\n", + " {\n", + " \"name\": \"tooltip\",\n", + " \"value\": {},\n", + " \"on\": [\n", + " {\"events\": \"rect:mouseover\", \"update\": \"datum\"},\n", + " {\"events\": \"rect:mouseout\", \"update\": \"{}\"},\n", + " ],\n", + " }\n", + " ],\n", + " \"scales\": [\n", + " {\n", + " \"name\": \"xscale\",\n", + " \"type\": \"band\",\n", + " \"domain\": {\"data\": \"table\", \"field\": \"category\"},\n", + " \"range\": \"width\",\n", + " \"padding\": 0.05,\n", + " \"round\": True,\n", + " },\n", + " {\n", + " \"name\": \"yscale\",\n", + " \"domain\": {\"data\": \"table\", \"field\": \"amount\"},\n", + " \"nice\": True,\n", + " \"range\": \"height\",\n", + " },\n", + " ],\n", + " \"axes\": [{\"orient\": \"bottom\", \"scale\": \"xscale\"}, {\"orient\": \"left\", \"scale\": \"yscale\"}],\n", + " \"marks\": [\n", + " {\n", + " \"type\": \"rect\",\n", + " \"from\": {\"data\": \"table\"},\n", + " \"encode\": {\n", + " \"enter\": {\n", + " \"x\": {\"scale\": \"xscale\", \"field\": \"category\"},\n", + " \"width\": {\"scale\": \"xscale\", \"band\": 1},\n", + " \"y\": {\"scale\": \"yscale\", \"field\": \"amount\"},\n", + " \"y2\": {\"scale\": \"yscale\", \"value\": 0},\n", + " },\n", + " \"update\": {\"fill\": {\"value\": \"steelblue\"}},\n", + " \"hover\": {\"fill\": {\"value\": \"red\"}},\n", + " },\n", + " },\n", + " {\n", + " \"type\": \"text\",\n", + " \"encode\": {\n", + " \"enter\": {\n", + " \"align\": {\"value\": \"center\"},\n", + " \"baseline\": {\"value\": \"bottom\"},\n", + " \"fill\": {\"value\": \"#333\"},\n", + " },\n", + " \"update\": {\n", + " \"x\": {\"scale\": \"xscale\", \"signal\": \"tooltip.category\", \"band\": 0.5},\n", + " \"y\": {\"scale\": \"yscale\", \"signal\": \"tooltip.amount\", \"offset\": -2},\n", + " \"text\": {\"signal\": \"tooltip.amount\"},\n", + " \"fillOpacity\": [{\"test\": \"datum === tooltip\", \"value\": 0}, {\"value\": 1}],\n", + " },\n", + " },\n", + " },\n", + " ],\n", " }\n", - " ]\n", - "})" + ")" ] }, { @@ -429,22 +418,30 @@ } ], "source": [ - "VegaLite({\n", - " \"$schema\": \"https://vega.github.io/schema/vega-lite/v4.json\",\n", - " \"description\": \"A simple bar chart with embedded data.\",\n", - " \"data\": {\n", - " \"values\": [\n", - " {\"a\": \"A\",\"b\": 28}, {\"a\": \"B\",\"b\": 55}, {\"a\": \"C\",\"b\": 43},\n", - " {\"a\": \"D\",\"b\": 91}, {\"a\": \"E\",\"b\": 81}, {\"a\": \"F\",\"b\": 53},\n", - " {\"a\": \"G\",\"b\": 19}, {\"a\": \"H\",\"b\": 87}, {\"a\": \"I\",\"b\": 52}\n", - " ]\n", - " },\n", - " \"mark\": \"bar\",\n", - " \"encoding\": {\n", - " \"x\": {\"field\": \"a\", \"type\": \"ordinal\"},\n", - " \"y\": {\"field\": \"b\", \"type\": \"quantitative\"}\n", - " }\n", - "})" + "VegaLite(\n", + " {\n", + " \"$schema\": \"https://vega.github.io/schema/vega-lite/v4.json\",\n", + " \"description\": \"A simple bar chart with embedded data.\",\n", + " \"data\": {\n", + " \"values\": [\n", + " {\"a\": \"A\", \"b\": 28},\n", + " {\"a\": \"B\", \"b\": 55},\n", + " {\"a\": \"C\", \"b\": 43},\n", + " {\"a\": \"D\", \"b\": 91},\n", + " {\"a\": \"E\", \"b\": 81},\n", + " {\"a\": \"F\", \"b\": 53},\n", + " {\"a\": \"G\", \"b\": 19},\n", + " {\"a\": \"H\", \"b\": 87},\n", + " {\"a\": \"I\", \"b\": 52},\n", + " ]\n", + " },\n", + " \"mark\": \"bar\",\n", + " \"encoding\": {\n", + " \"x\": {\"field\": \"a\", \"type\": \"ordinal\"},\n", + " \"y\": {\"field\": \"b\", \"type\": \"quantitative\"},\n", + " },\n", + " }\n", + ")" ] }, { diff --git a/galata/README.md b/galata/README.md index a49e3bf53c05..65f294f57a4d 100644 --- a/galata/README.md +++ b/galata/README.md @@ -62,17 +62,12 @@ specific options. Create `jupyter_server_test_config.py` with the following content. ```py -from tempfile import mkdtemp +from jupyterlab.galata import configure_jupyter_server -c.ServerApp.port = 8888 -c.ServerApp.port_retries = 0 -c.ServerApp.open_browser = False +configure_jupyter_server(c) -c.ServerApp.root_dir = mkdtemp(prefix='galata-test-') -c.ServerApp.token = "" -c.ServerApp.password = "" -c.ServerApp.disable_check_xsrf = True -c.LabApp.expose_app_in_browser = True +# Uncomment to set server log level to debug level +# c.ServerApp.log_level = "DEBUG" ``` Then start the server with: @@ -81,6 +76,8 @@ Then start the server with: jupyter lab --config jupyter_server_test_config.py ``` +> If you need to customize the set up for galata, you can look at the [`configure_jupyter_server`](https://github.com/jupyterlab/jupyterlab/tree/4.0.x/jupyterlab/galata/__init__.py) definition. + ### Run test project ```bash @@ -109,7 +106,7 @@ Test assets (including test videos) will be saved in a `test-results` folder and report will be created in `playwright-report` folder. That report can be see by running: ```bash -http-server ./playwright-report -a localhost -o +jlpm playwright show-report ``` ## User advices @@ -214,6 +211,73 @@ steps were successful. Its content will look like that: > This will only work if the authentication is stored in a cookie and you can access the Jupyter > app directly when that cookie is set. +## Helpers + +### Listen to dialogs + +You can add a listener that will be triggered when a JupyterLab dialog is shown: + +```typescript +await page.evaluate(() => { + window.galata.on('dialog', (dialog: Dialog | null) => { + // Use the dialog + // You can for instance reject it + // dialog.reject() + }); +}); +``` + +The listener will be called when a dialog is started and when it is closed (in that case `dialog == null`). + +You can stop listening to the event with: + +```typescript +await page.evaluate(() => { + window.galata.off('dialog', listener); +}); +``` + +Or you can listen to a single event with: + +```typescript +await page.evaluate(() => { + window.galata.once('dialog', listener); +}); +``` + +### Listen to notification + +You can add a listener that will be triggered when a JupyterLab dialog is shown: + +```typescript +await page.evaluate(() => { + window.galata.on( + 'notification', + (notification: Notification.INotification) => { + // Use the notification + } + ); +}); +``` + +The listener will be called when a notification is created or updated. + +You can stop listening to the event with: + +```typescript +await page.evaluate(() => { + window.galata.off('notification', listener); +}); +``` + +Or you can listen to a single event with: + +```typescript +await page.evaluate(() => { + window.galata.once('notification', listener); +}); +``` + ## Fixtures Here are the new test fixture introduced by Galata on top of [Playwright fixtures](https://playwright.dev/docs/api/class-fixtures). @@ -249,8 +313,7 @@ test('Open language menu', async ({ page }) => { if (request.method() === 'GET') { return route.fulfill({ status: 200, - body: - '{"data": {"en": {"displayName": "English", "nativeName": "English"}}, "message": ""}' + body: '{"data": {"en": {"displayName": "English", "nativeName": "English"}}, "message": ""}' }); } else { return route.continue(); @@ -370,6 +433,20 @@ test('should return mocked settings', async ({ page }) => { }); ``` +### mockUser + +- type: boolean | Partial\ + +Mock JupyterLab user in-memory or not. + +Possible values are: + +- true (default): JupyterLab user will be mocked on a per test basis +- false: JupyterLab user won't be mocked (It will be a random user so snapshots won't match) +- Record: Initial JupyterLab user - Mapping (user attribute, value). + +By default the user is stored in-memory. + ### sessions - type: \ | null> @@ -479,7 +556,7 @@ Benchmark of JupyterLab is done using Playwright. The actions measured are: Two files are tested: a notebook with many code cells and another with many markdown cells. The test is run on the CI by comparing the result in the commit at which a PR branch started and the PR branch head on -the same CI job to ensure using the same hardware.\ +the same CI job to ensure using the same hardware. The benchmark job is triggered on: - Approved PR review @@ -500,7 +577,7 @@ A special report will be generated in the folder `benchmark-results` that will c - `lab-benchmark.vl.json`: The [_Vega-Lite_](https://vega.github.io/vega-lite) description used to produce the figure. The reference, tagged _expected_, is stored in `lab-benchmark-expected.json`. It can be -updated using the `-u` option of Playwright; i.e. `jlpm run test:benchmark -u`. +created using the `-u` option of Playwright; i.e. `jlpm run test:benchmark -u`. ### Benchmark parameters @@ -508,7 +585,8 @@ The benchmark can be customized using the following environment variables: - `BENCHMARK_NUMBER_SAMPLES`: Number of samples to compute the execution time distribution; default 20. - `BENCHMARK_OUTPUTFILE`: Benchmark result output file; default `benchmark.json`. It is overridden in the [`playwright-benchmark.config.js`](playwright-benchmark.config.js). -- `BENCHMARK_REFERENCE`: Reference name of the data; default is `actual` for current data and `expected` for the reference. +- `BENCHMARK_REFERENCE`: Reference name of the data; default is `actual`. +- `BENCHMARK_EXPECTED_REFERENCE`: Reference name of the reference data; default is `expected`. ## Development diff --git a/galata/extension/README.md b/galata/extension/README.md new file mode 100644 index 000000000000..67f7377e82da --- /dev/null +++ b/galata/extension/README.md @@ -0,0 +1,4 @@ +# @jupyterlab/galata-extension + +This package is a JupyterLab extension easing access to some JupyterLab elements +for integration testing with `@jupyterlab/galata`. diff --git a/galata/extension/package.json b/galata/extension/package.json new file mode 100644 index 000000000000..77db9e9000ae --- /dev/null +++ b/galata/extension/package.json @@ -0,0 +1,56 @@ +{ + "name": "@jupyterlab/galata-extension", + "version": "5.0.8", + "private": true, + "description": "JupyterLab UI Testing Framework Extension.", + "keywords": [ + "jupyter", + "jupyterlab", + "jupyterlab-extension" + ], + "homepage": "https://github.com/jupyterlab/jupyterlab", + "bugs": { + "url": "https://github.com/jupyterlab/jupyterlab/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/jupyterlab/jupyterlab.git" + }, + "license": "BSD-3-Clause", + "author": "Project Jupyter", + "main": "../lib/extension/index.js", + "types": "../lib/extension/index.d.ts", + "files": [ + "../lib/extension/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}" + ], + "scripts": { + "build": "npm run build:lib && npm run build:labextension", + "build:labextension": "node ../../node_modules/@jupyterlab/builder/lib/build-labextension.js --core-path ../../dev_mode --development .", + "build:lib": "tsc", + "clean": "npm run clean:lib && npm run clean:labextension", + "clean:labextension": "rimraf ../../jupyterlab/galata/@jupyterlab", + "clean:lib": "rimraf ../lib/extension tsconfig.tsbuildinfo" + }, + "dependencies": { + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/cells": "^4.0.8", + "@jupyterlab/debugger": "^4.0.8", + "@jupyterlab/docmanager": "^4.0.8", + "@jupyterlab/nbformat": "^4.0.8", + "@jupyterlab/notebook": "^4.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@lumino/algorithm": "^2.0.1", + "@lumino/coreutils": "^2.1.2", + "@lumino/signaling": "^2.1.2" + }, + "devDependencies": { + "@jupyterlab/builder": "^4.0.8", + "rimraf": "~3.0.0", + "typescript": "~5.0.4" + }, + "jupyterlab": { + "extension": true, + "outputDir": "../../jupyterlab/galata/@jupyterlab/galata-extension" + } +} diff --git a/galata/extension/src/global.ts b/galata/extension/src/global.ts new file mode 100644 index 000000000000..bd42a1e9b23f --- /dev/null +++ b/galata/extension/src/global.ts @@ -0,0 +1,751 @@ +/* eslint-disable @typescript-eslint/ban-types */ +// Copyright (c) Jupyter Development Team. +// Copyright (c) Bloomberg Finance LP. +// Distributed under the terms of the Modified BSD License. + +import type { IRouter, JupyterFrontEnd } from '@jupyterlab/application'; +import type { + Dialog, + IWidgetTracker, + Notification, + NotificationManager +} from '@jupyterlab/apputils'; +import type { Cell, CodeCellModel, MarkdownCell } from '@jupyterlab/cells'; +import type * as nbformat from '@jupyterlab/nbformat'; +import type { NotebookPanel } from '@jupyterlab/notebook'; +import { findIndex } from '@lumino/algorithm'; +import { Signal } from '@lumino/signaling'; +import { + IGalataInpage, + INotebookRunCallback, + IPluginNameToInterfaceMap, + IWaitForSelectorOptions, + PLUGIN_ID_GALATA_HELPERS +} from './tokens'; + +const PLUGIN_ID_DOC_MANAGER = '@jupyterlab/docmanager-extension:manager'; +const PLUGIN_ID_ROUTER = '@jupyterlab/application-extension:router'; + +/** + * In-Page Galata helpers + */ +export class GalataInpage implements IGalataInpage { + /** + * Get an application plugin + * + * @param pluginId Plugin ID + * @returns Application plugin + */ + async getPlugin( + pluginId: K + ): Promise { + return new Promise((resolve, reject) => { + const app = this._app; + const hasPlugin = app.hasPlugin(pluginId); + + if (hasPlugin) { + try { + const appAny = app as any; + const plugin: any = appAny._plugins + ? appAny._plugins.get(pluginId) + : undefined; + if (plugin.activated) { + resolve(plugin.service); + } else { + void app.activatePlugin(pluginId).then(response => { + resolve(plugin.service); + }); + } + } catch (error) { + console.error('Failed to get plugin', error); + } + } + }); + } + + /** + * Get the Jupyter notifications + * + * @returns Jupyter Notifications + */ + async getNotifications(): Promise { + const plugin = await this.getPlugin(PLUGIN_ID_GALATA_HELPERS); + return plugin?.notifications.notifications ?? []; + } + + /** + * Disconnect a listener to new Jupyter dialog events. + * + * @param event Event type + * @param listener Event listener + */ + off(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + /** + * Disconnect a listener to new or updated Jupyter notification events. + * + * @param event Event type + * @param listener Event listener + */ + off( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + off(event: 'dialog' | 'notification', listener: (arg: any) => void): void { + const callback = this.listeners.get(listener); + if (callback) { + this.getPlugin(PLUGIN_ID_GALATA_HELPERS) + .then(plugin => { + if (!plugin) { + return; + } + switch (event) { + case 'dialog': + plugin.dialogs.currentChanged.disconnect(callback); + break; + case 'notification': + plugin.notifications.changed.disconnect(callback); + break; + } + this.listeners.delete(listener); + }) + .catch(reason => { + console.log( + `Failed to disconnect listener for '${event}' event.`, + reason + ); + }); + } + } + + /** + * Connect a listener to new Jupyter dialog events. + * + * @param event Event type + * @param listener Event listener + */ + on(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + on( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + /** + * Connect a listener to new or updated Jupyter notification events. + * + * @param event Event type + * @param listener Event listener + */ + on(event: 'dialog' | 'notification', listener: (arg: any) => void): void { + this.getPlugin(PLUGIN_ID_GALATA_HELPERS) + .then(plugin => { + switch (event) { + case 'dialog': + { + const callback = ( + tracker: IWidgetTracker>, + dialog: Dialog | null + ) => { + listener(dialog); + }; + this.listeners.set(listener, callback); + plugin?.dialogs.currentChanged.connect(callback); + } + break; + case 'notification': + { + const callback = ( + manager: NotificationManager, + notification: Notification.IChange + ) => { + if (notification.type !== 'removed') { + listener(notification.notification); + } + }; + this.listeners.set(listener, callback); + plugin?.notifications.changed.connect(callback); + } + break; + } + }) + .catch(reason => { + console.error( + `Failed to add listener to JupyterLab dialog event:\n${reason}` + ); + }); + } + + /** + * Connect a listener to the next new Jupyter dialog event. + * + * @param event Event type + * @param listener Event listener + */ + once(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + /** + * Connect a listener to the next new or updated Jupyter notification event. + * + * @param event Event type + * @param listener Event listener + */ + once( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + once(event: 'dialog' | 'notification', listener: (arg: any) => void): void { + const onceListener = (arg: any) => { + try { + listener(arg); + } finally { + this.off(event as any, onceListener); + } + }; + this.on(event as any, onceListener); + } + + /** + * Wait for a function to finish for max. timeout milliseconds + * + * @param fn Function + * @param timeout Timeout + */ + async waitForFunction(fn: Function, timeout?: number): Promise { + return new Promise((resolve, reject) => { + let checkTimer: number | null = null; + let timeoutTimer: number | null = null; + const check = async () => { + checkTimer = null; + if (await Promise.resolve(fn())) { + if (timeoutTimer) { + clearTimeout(timeoutTimer); + } + resolve(); + } else { + checkTimer = window.setTimeout(check, 200); + } + }; + + void check(); + + if (timeout) { + timeoutTimer = window.setTimeout(() => { + timeoutTimer = null; + if (checkTimer) { + clearTimeout(checkTimer); + } + reject(new Error('Timed out waiting for condition to be fulfilled.')); + }, timeout); + } + }); + } + + /** + * Waits for the given `timeout` in milliseconds. + * + * @param timeout A timeout to wait for + */ + async waitForTimeout(timeout: number): Promise { + return new Promise(resolve => { + setTimeout(() => { + resolve(); + }, timeout); + }); + } + + /** + * Wait for a condition to fulfill or for a certain time + * + * @param condition Condition or timeout to wait for + * @param timeout Timeout + */ + async waitFor(condition: Function | number, timeout?: number): Promise { + const conditionType = typeof condition; + + if (conditionType === 'function') { + return this.waitForFunction(condition as Function, timeout); + } else if (conditionType === 'number') { + return this.waitForTimeout(condition as number); + } + } + + /** + * Wait for the route to be on path and close all documents + * + * @param path Path to monitor + */ + async waitForLaunch(path = '/lab'): Promise { + let resolver: () => void; + const delegate = new Promise(resolve => { + resolver = resolve; + }); + const router = await this.getPlugin(PLUGIN_ID_ROUTER); + const docManager = await this.getPlugin(PLUGIN_ID_DOC_MANAGER); + + const listener = async (sender: IRouter, args: IRouter.ILocation) => { + if (args.path === path) { + router?.routed.disconnect(listener); + await docManager?.closeAll(); + resolver(); + } + }; + + router?.routed.connect(listener); + return delegate; + } + + /** + * Wait for an element to be found from a CSS selector + * + * @param selector CSS selector + * @param node Element + * @param options Options + * @returns Selected element + */ + async waitForSelector( + selector: string, + node?: Element, + options?: IWaitForSelectorOptions + ): Promise { + const waitForHidden = options && options.hidden; + + return new Promise((resolve, reject) => { + const timer = setInterval(() => { + const parent = node || document; + const found = parent.querySelector(selector); + if (waitForHidden) { + if (!found) { + clearInterval(timer); + resolve(null); + } + } else if (found) { + clearInterval(timer); + resolve(found); + } + }, 200); + }); + } + + /** + * Wait for an element to be found from a XPath + * + * @param selector CSS selector + * @param node Element + * @param options Options + * @returns Selected element + */ + async waitForXPath( + selector: string, + node?: Element, + options?: IWaitForSelectorOptions + ): Promise { + const waitForHidden = options && options.hidden; + + return new Promise((resolve, reject) => { + const timer = setInterval(() => { + const parent = node || document; + const iterator = document.evaluate( + selector, + parent, + null, + XPathResult.UNORDERED_NODE_ITERATOR_TYPE, + null + ); + const found = iterator && iterator.iterateNext(); + if (waitForHidden) { + if (!found) { + clearInterval(timer); + resolve(null); + } + } else if (found) { + clearInterval(timer); + resolve(found); + } + }, 200); + }); + } + + /** + * Delete all cells of the active notebook + */ + async deleteNotebookCells(): Promise { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + const nb = nbPanel.content; + + void this._app.commands.execute('notebook:delete-cell'); + + nb.update(); + } + /** + * Add a cell to the active notebook + * + * @param cellType Cell type + * @param source Cell input source + * @returns Action success result + */ + addNotebookCell(cellType: nbformat.CellType, source: string): boolean { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + const nb = nbPanel.content; + + if (nb !== null) { + void this._app.commands.execute('notebook:insert-cell-below'); + + if (nb.model) { + const sharedModel = nb.model.sharedModel; + sharedModel.insertCell(sharedModel.cells.length, { + cell_type: cellType, + source + }); + } + nb.update(); + } else { + return false; + } + + return true; + } + + /** + * Reset execution count of one or all cells. + * + * @param cellIndex Cell index + */ + resetExecutionCount(cellIndex?: number): void { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + const nb = nbPanel.content; + + if (nb) { + if (nb.model) { + if (cellIndex === undefined) { + for (const cell of nb.model.cells) { + switch (cell.type) { + case 'code': + (cell as CodeCellModel).executionCount = null; + break; + } + } + } else if (nb.model.cells.get(cellIndex)?.type === 'code') { + (nb.model.cells.get(cellIndex) as CodeCellModel).executionCount = + null; + } + } + } + } + + /** + * Set the type and content of a cell in the active notebook + * + * @param cellIndex Cell index + * @param cellType Cell type + * @param source Cell input source + * @returns Action success status + */ + setNotebookCell( + cellIndex: number, + cellType: nbformat.CellType, + source: string + ): boolean { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + const nb = nbPanel.content; + + if (nb) { + const numCells = nb.widgets.length; + if (cellIndex < 0 || cellIndex >= numCells) { + return false; + } + + if (nb.model) { + const sharedModel = nb.model.sharedModel; + sharedModel.transact(() => { + sharedModel.deleteCell(cellIndex); + sharedModel.insertCell(cellIndex, { cell_type: cellType, source }); + }); + } + nb.update(); + } else { + return false; + } + + return true; + } + + /** + * Test if a cell is selected in the active notebook + * + * @param cellIndex Cell index + * @returns Whether the cell is selected or not + */ + isNotebookCellSelected(cellIndex: number): boolean { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + const nb = nbPanel.content; + + const numCells = nb.widgets.length; + if (cellIndex < 0 || cellIndex >= numCells) { + return false; + } + + return nb.isSelected(nb.widgets[cellIndex]); + } + + /** + * Save the active notebook + */ + async saveActiveNotebook(): Promise { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + await nbPanel.context.save(); + } + + /** + * Wait for a Markdown cell to be rendered + * + * @param cell Cell + */ + async waitForMarkdownCellRendered(cell: MarkdownCell): Promise { + if (!cell.inViewport) { + return; + } + + await cell.ready; + + if (cell.rendered) { + return; + } + + let resolver: (value: void | PromiseLike) => void; + const delegate = new Promise(resolve => { + resolver = resolve; + }); + + const onRenderedChanged = () => { + Signal.disconnectReceiver(onRenderedChanged); + resolver(); + }; + + cell.renderedChanged.connect(onRenderedChanged); + + return delegate; + } + + /** + * Wait for a cell to be run + * + * @param cell Cell + * @param timeout Timeout + */ + async waitForCellRun(cell: Cell, timeout = 2000): Promise { + const model = cell.model; + const code = model.sharedModel.getSource(); + if (!code.trim()) { + return; + } + + const cellType = cell.model.type; + if (cellType === 'markdown') { + await this.waitForMarkdownCellRendered(cell as MarkdownCell); + return; + } else if (cellType === 'raw') { + return; + } else { + // 'code' + let resolver: () => void; + const delegate = new Promise(resolve => { + resolver = resolve; + }); + + let numTries = 0; + let timer: any = null; + let timeoutTimer: any = null; + + const clearAndResolve = () => { + clearInterval(timer); + timer = null; + clearTimeout(timeoutTimer); + timeoutTimer = null; + resolver(); + }; + + const startTimeout = () => { + if (!timeoutTimer) { + timeoutTimer = setTimeout(() => { + clearAndResolve(); + }, timeout); + } + }; + + const checkIfDone = () => { + if ((cell.model as CodeCellModel).executionCount !== null) { + if (!cell.inViewport) { + clearAndResolve(); + return; + } + + const output = cell.node.querySelector( + '.jp-Cell-outputArea .jp-OutputArea-output' + ); + + if (output) { + if (output.textContent === 'Loading widget...') { + startTimeout(); + } else { + clearAndResolve(); + } + } else { + if (numTries > 0) { + clearAndResolve(); + } + } + } else { + startTimeout(); + } + numTries++; + }; + + checkIfDone(); + + timer = setInterval(() => { + checkIfDone(); + }, 200); + return delegate; + } + } + + /** + * Run the active notebook cell by cell + * and execute the callback after each cell execution + * + * @param callback Callback + */ + async runActiveNotebookCellByCell( + callback?: INotebookRunCallback + ): Promise { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + const notebook = nbPanel.content; + if (!notebook.widgets) { + console.error('NOTEBOOK CELL PROBLEM', notebook); + } + const numCells = notebook.widgets.length; + + if (numCells === 0) { + return; + } + + void this._app.commands.execute('notebook:deselect-all'); + + for (let i = 0; i < numCells; ++i) { + const cell = notebook.widgets[i]; + notebook.activeCellIndex = i; + notebook.select(cell); + + await this._app.commands.execute('notebook:run-cell'); + + await this.waitForCellRun(cell); + + if (callback?.onAfterCellRun) { + await callback.onAfterCellRun(i); + } + + if (callback?.onBeforeScroll) { + await callback.onBeforeScroll(); + } + + await notebook.scrollToItem(i).catch(reason => { + // no-op + }); + + if (callback?.onAfterScroll) { + await callback.onAfterScroll(); + } + } + } + + /** + * Test if one or all cells have an execution number. + * + * @param cellIndex Cell index + * @returns Whether the cell was executed or not + * + * ### Notes + * It checks that no cells have a `null` execution count. + */ + haveBeenExecuted(cellIndex?: number): boolean { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + const nb = nbPanel.content; + + let counter = 0; + if (nb) { + if (nb.model) { + if (cellIndex === undefined) { + for (const cell of nb.model.cells) { + if (cell.type === 'code') { + counter += + cell.sharedModel.getSource().length > 0 && + (cell as CodeCellModel).executionCount === null + ? 1 + : 0; + } + } + } else { + const cell = nb.model.cells.get(cellIndex); + if (cell?.type === 'code') { + counter += + cell.sharedModel.getSource().length > 0 && + (cell as CodeCellModel).executionCount === null + ? 1 + : 0; + } + } + } + } + + return counter === 0; + } + + /** + * Get the index of a toolbar item + * + * @param itemName Item name + * @returns Index + */ + getNotebookToolbarItemIndex(itemName: string): number { + const nbPanel = this._app.shell.currentWidget as NotebookPanel; + return findIndex(nbPanel.toolbar.names(), name => name === itemName); + } + + /** + * Test if a element is visible or not + * + * @param el Element + * @returns Test result + */ + isElementVisible(el: HTMLElement): boolean { + return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); + } + + /** + * Set the application theme + * + * @param themeName Theme name + */ + async setTheme(themeName: string): Promise { + await this._app.commands.execute('apputils:change-theme', { + theme: themeName + }); + + await this.waitFor(async () => { + return document.body.dataset.jpThemeName === themeName; + }); + } + + /** + * Application object + */ + get app(): JupyterFrontEnd { + if (!this._app) { + this._app = window.jupyterapp; + } + return this._app; + } + + private _app: JupyterFrontEnd; + protected listeners = new WeakMap< + (arg: unknown) => void, + (sender: unknown, args: unknown) => void + >(); +} diff --git a/galata/extension/src/index.ts b/galata/extension/src/index.ts new file mode 100644 index 000000000000..e655be55260e --- /dev/null +++ b/galata/extension/src/index.ts @@ -0,0 +1,42 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { + JupyterFrontEnd, + JupyterFrontEndPlugin +} from '@jupyterlab/application'; +import { Dialog, Notification } from '@jupyterlab/apputils'; +import { GalataInpage } from './global'; +import { IGalataHelpers, PLUGIN_ID_GALATA_HELPERS } from './tokens'; + +export type { + IGalataInpage, + INotebookRunCallback, + IPluginNameToInterfaceMap, + IWaitForSelectorOptions +} from './tokens'; + +export { IGalataHelpers } from './tokens'; + +/** + * Galata in-page object + */ +window.galata = new GalataInpage(); +/** + * Galata in-page object + * @deprecated + */ +window.galataip = window.galata; + +const galataPlugin: JupyterFrontEndPlugin = { + id: PLUGIN_ID_GALATA_HELPERS, + autoStart: true, + activate: (app: JupyterFrontEnd): IGalataHelpers => { + return Object.freeze({ + notifications: Notification.manager, + dialogs: Dialog.tracker + }); + } +}; + +export default galataPlugin; diff --git a/galata/extension/src/tokens.ts b/galata/extension/src/tokens.ts new file mode 100644 index 000000000000..1a30c3c99fa3 --- /dev/null +++ b/galata/extension/src/tokens.ts @@ -0,0 +1,293 @@ +// Copyright (c) Jupyter Development Team. +// Copyright (c) Bloomberg Finance LP. +// Distributed under the terms of the Modified BSD License. + +import type { JupyterFrontEnd } from '@jupyterlab/application'; +import type { IRouter } from '@jupyterlab/application'; +import type { + Dialog, + Notification, + NotificationManager, + WidgetTracker +} from '@jupyterlab/apputils'; +import type { IDebugger } from '@jupyterlab/debugger'; +import type { IDocumentManager } from '@jupyterlab/docmanager'; +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; +import { Token } from '@lumino/coreutils'; + +declare global { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + /** + * Access Jupyter Application object + */ + jupyterapp: JupyterFrontEnd; + /** + * Access to Galata In-Page helpers + * + * Those helpers are injected through a JupyterLab extension + */ + galata: IGalataInpage; + /** + * Access to Galata In-Page helpers + * + * @deprecated since v4 + * Those helpers are injected through a JupyterLab extension + */ + galataip: IGalataInpage; + } +} + +/** + * Galata in-page extension helpers. + */ +export const PLUGIN_ID_GALATA_HELPERS = '@jupyterlab/galata-extension:helpers'; + +/** + * Static objects exposed. + */ +export interface IGalataHelpers { + /** + * JupyterLab dialogs tracker. + */ + readonly dialogs: WidgetTracker>; + /** + * JupyterLab notifications manager. + */ + readonly notifications: NotificationManager; +} + +/** + * Test token exposing some static JupyterLab objects. + */ +export const IGalataHelpers = new Token( + '@jupyterlab/galata-extension:IGalataHelpers' +); + +/** + * Cell execution callbacks interface + */ +export interface INotebookRunCallback { + /** + * Callback before scrolling to the cell + */ + onBeforeScroll?: () => Promise; + /** + * Callback after scrolling to the cell + */ + onAfterScroll?: () => Promise; + /** + * Callback after cell execution + */ + onAfterCellRun?: (cellIndex: number) => Promise; +} + +/** + * waitForSelector options + */ +export interface IWaitForSelectorOptions { + /** + * Test for the element to be hidden. + */ + hidden?: boolean; +} + +export interface IPluginNameToInterfaceMap { + [PLUGIN_ID_GALATA_HELPERS]: IGalataHelpers; + '@jupyterlab/application-extension:router': IRouter; + '@jupyterlab/docmanager-extension:manager': IDocumentManager; + '@jupyterlab/apputils-extension:settings': ISettingRegistry; + '@jupyterlab/debugger-extension:service': IDebugger; +} + +/** + * Galata In-Page interface + */ +export interface IGalataInpage { + /** + * Delete all cells of the active notebook + */ + deleteNotebookCells(): Promise; + + /** + * Get the index of a toolbar item + * + * @param itemName Item name + * @returns Index + */ + getNotebookToolbarItemIndex(itemName: string): number; + + /** + * Get an application plugin + * + * @param pluginId Plugin ID + * @returns Application plugin + */ + getPlugin( + pluginId: K + ): Promise; + + /** + * Get the Jupyter notifications. + * + * @returns Jupyter Notifications + */ + getNotifications(): Promise; + + /** + * Test if one or all cells have an execution number. + * + * @param cellIndex Cell index + * @returns Whether the cell was executed or not + * + * ### Notes + * It checks that no cells have a `null` execution count. + */ + haveBeenExecuted(cellIndex?: number): boolean; + + /** + * Test if a cell is selected in the active notebook + * + * @param cellIndex Cell index + * @returns Whether the cell is selected or not + */ + isNotebookCellSelected(cellIndex: number): boolean; + + /** + * Test if a element is visible or not + * + * @param el Element + * @returns Test result + */ + isElementVisible(el: HTMLElement): boolean; + + /** + * Disconnect a listener to new Jupyter dialog events. + * + * @param event Event type + * @param listener Event listener + */ + off(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + /** + * Disconnect a listener to new or updated Jupyter notification events. + * + * @param event Event type + * @param listener Event listener + */ + off( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + + /** + * Connect a listener to new Jupyter dialog events. + * + * @param event Event type + * @param listener Event listener + */ + on(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + + /** + * Connect a listener to new or updated Jupyter notification events. + * + * @param event Event type + * @param listener Event listener + */ + on( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + + /** + * Connect a listener to the next new Jupyter dialog event. + * + * @param event Event type + * @param listener Event listener + */ + once(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + + /** + * Connect a listener to the next new or updated Jupyter notification event. + * + * @param event Event type + * @param listener Event listener + */ + once( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + + /** + * Save the active notebook + */ + saveActiveNotebook(): Promise; + + /** + * Set the application theme + * + * @param themeName Theme name + */ + setTheme(themeName: string): Promise; + + /** + * Reset execution count of one or all cells. + * + * @param cellIndex Cell index + */ + resetExecutionCount(cellIndex?: number): void; + + /** + * Run the active notebook cell by cell + * and execute the callback after each cell execution + * + * @param callback Callback + */ + runActiveNotebookCellByCell(callback?: INotebookRunCallback): Promise; + + /** + * Wait for the route to be on path and close all documents + * + * @param path Path to monitor + */ + waitForLaunch(path?: string): Promise; + + /** + * Wait for an element to be found from a CSS selector + * + * @param selector CSS selector + * @param node Element + * @param options Options + * @returns Selected element + */ + waitForSelector( + selector: string, + node?: Element, + options?: IWaitForSelectorOptions + ): Promise; + + /** + * Waits for the given `timeout` in milliseconds. + * + * @param timeout A timeout to wait for + */ + waitForTimeout(duration: number): Promise; + + /** + * Wait for an element to be found from a XPath + * + * @param selector CSS selector + * @param node Element + * @param options Options + * @returns Selected element + */ + waitForXPath( + selector: string, + node?: Element, + options?: IWaitForSelectorOptions + ): Promise; + + /** + * Application object + */ + readonly app: JupyterFrontEnd; +} diff --git a/galata/extension/tsconfig.json b/galata/extension/tsconfig.json new file mode 100644 index 000000000000..c98b0c0868e5 --- /dev/null +++ b/galata/extension/tsconfig.json @@ -0,0 +1,34 @@ +{ + "extends": "../../tsconfigbase", + "compilerOptions": { + "outDir": "../lib/extension", + "rootDir": "src" + }, + "include": ["src/*"], + "references": [ + { + "path": "../../packages/application" + }, + { + "path": "../../packages/apputils" + }, + { + "path": "../../packages/cells" + }, + { + "path": "../../packages/debugger" + }, + { + "path": "../../packages/docmanager" + }, + { + "path": "../../packages/nbformat" + }, + { + "path": "../../packages/notebook" + }, + { + "path": "../../packages/settingregistry" + } + ] +} diff --git a/galata/jupyter_server_test_config.py b/galata/jupyter_server_test_config.py index 0e659bcb7060..346f0c12c78c 100644 --- a/galata/jupyter_server_test_config.py +++ b/galata/jupyter_server_test_config.py @@ -1,17 +1,10 @@ -import getpass -from tempfile import mkdtemp +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. -# Test if we are running in a docker -if getpass.getuser() == "jovyan": - c.ServerApp.ip = "0.0.0.0" +from jupyterlab.galata import configure_jupyter_server -c.ServerApp.port = 8888 -c.ServerApp.port_retries = 0 -c.ServerApp.open_browser = False +configure_jupyter_server(c) c.LabApp.dev_mode = True -c.ServerApp.root_dir = mkdtemp(prefix="galata-test-") -c.ServerApp.token = "" -c.ServerApp.password = "" -c.ServerApp.disable_check_xsrf = True -c.LabApp.expose_app_in_browser = True +# Uncomment to set server log level to debug level +# c.ServerApp.log_level = "DEBUG" diff --git a/galata/media/galata-logo.svg b/galata/media/galata-logo.svg index 5da313b25012..42982e5a3813 100644 --- a/galata/media/galata-logo.svg +++ b/galata/media/galata-logo.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/galata/package.json b/galata/package.json index dc754d62f5ea..727026a2330b 100644 --- a/galata/package.json +++ b/galata/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/galata", - "version": "4.5.6", + "version": "5.0.8", "description": "JupyterLab UI Testing Framework", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -12,81 +12,63 @@ }, "license": "BSD-3-Clause", "author": "Project Jupyter", - "sideEffects": [ - "style/*.css", - "style/index.js" - ], "main": "lib/index.js", "types": "lib/index.d.ts", - "style": "style/index.css", "directories": { "lib": "lib/" }, "files": [ "lib/**/*.{js,ts,map}", - "!lib/inpage/index.*", "style/index.css", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { - "build": "jlpm run clean && jlpm run build:galata && jlpm run build:inpage", - "build:all": "npm run build", + "build": "npm run build:extension && npm run build:galata", + "build:extension": "cd extension && npm run build && cd ..", "build:galata": "tsc -b", - "build:inpage": "webpack --mode=production", - "clean": "rimraf lib tsconfig.tsbuildinfo", + "clean": "npm run clean:extension && rimraf lib tsconfig.tsbuildinfo", + "clean:extension": "cd extension && npm run clean && cd ..", "start": "jupyter lab --config ./jupyter_server_test_config.py", - "start:detached": "(jlpm run start&)", - "start:doc": "mkdir -p /tmp/dummy-server/lab && python -m http.server -d /tmp/dummy-server 8888", + "start:detached": "(npm run start&)", + "start:doc": "PYTHONWARNINGS=ignore jupyter lab --config ./jupyter_server_test_config.py --extensions-in-dev-mode", "test": "playwright test", + "test:base": "playwright test --project galata jupyterlab", + "test:base:update": "playwright test --project galata jupyterlab --update-snapshots", "test:benchmark": "jlpm run test -c playwright-benchmark.config.js", "test:benchmark:update": "BENCHMARK_NUMBER_SAMPLES=1 jlpm run test -c playwright-benchmark.config.js --update-snapshots", "test:debug": "PWDEBUG=1 playwright test", - "test:doc": "echo \"No documentation tests\"", - "test:doc:update": "echo \"No documentation tests\"", - "test:report": "http-server ./playwright-report -a localhost -o", - "test:update": "playwright test --update-snapshots && jlpm test:benchmark:update" + "test:doc": "jlpm run test --project documentation", + "test:doc:update": "jlpm run test --project documentation --update-snapshots", + "test:report": "playwright show-report", + "test:update": "jlpm test:base:update && jlpm test:benchmark:update" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/cells": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/docmanager": "^3.6.6", - "@jupyterlab/nbformat": "^3.6.6", - "@jupyterlab/notebook": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/coreutils": "^1.11.0", - "@playwright/test": "^1.16.2", - "@stdlib/stats": "^0.0.13", - "fs-extra": "^9.0.1", - "http-server": "^13.0.0", - "json5": "^2.1.1", - "node-fetch": "^2.6.0", + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/debugger": "^4.0.8", + "@jupyterlab/docmanager": "^4.0.8", + "@jupyterlab/nbformat": "^4.0.8", + "@jupyterlab/notebook": "^4.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@lumino/coreutils": "^2.1.2", + "@playwright/test": "^1.32.2", + "@stdlib/stats": "~0.0.13", + "fs-extra": "^10.1.0", + "json5": "^2.2.3", "path": "~0.12.7", "systeminformation": "^5.8.6", "vega": "^5.20.0", - "vega-lite": "^5.1.0", + "vega-lite": "^5.6.1", "vega-statistics": "^1.7.9" }, "devDependencies": { - "@types/node-fetch": "^2.5.4", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", - "raw-loader": "~4.0.0", "rimraf": "~3.0.0", - "source-map-loader": "~1.0.2", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "svgo-loader": "^2.2.1", - "ts-loader": "^6.2.1", - "typescript": "~4.1.3", - "url-loader": "~4.1.0", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0" + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" - }, - "styleModule": "style/index.js" + } } diff --git a/galata/playwright.config.js b/galata/playwright.config.js index cec982e2ddbc..46d6ddd9ba14 100644 --- a/galata/playwright.config.js +++ b/galata/playwright.config.js @@ -6,6 +6,20 @@ var baseConfig = require('@jupyterlab/galata/lib/playwright-config'); module.exports = { ...baseConfig, projects: [ + { + name: 'documentation', + // Try one retry as some tests are flaky + retries: process.env.CI ? 2 : 0, + testMatch: 'test/documentation/**/*.test.ts', + testIgnore: '**/.ipynb_checkpoints/**', + timeout: 90000, + use: { + launchOptions: { + // Force slow motion + slowMo: 30 + } + } + }, { name: 'galata', testMatch: 'test/galata/**', @@ -14,11 +28,16 @@ module.exports = { { name: 'jupyterlab', testMatch: 'test/jupyterlab/**', - testIgnore: '**/.ipynb_checkpoints/**' + testIgnore: '**/.ipynb_checkpoints/**', + use: { + contextOptions: { + permissions: ['clipboard-read', 'clipboard-write'] + } + } } ], // Switch to 'always' to keep raw assets for all tests preserveOutput: 'failures-only', // Breaks HTML report if use.video == 'on' // Try one retry as some tests are flaky - retries: 1 + retries: process.env.CI ? 1 : 0 }; diff --git a/galata/src/benchmarkReporter.ts b/galata/src/benchmarkReporter.ts index 64bf7437be8e..b5b081c13879 100644 --- a/galata/src/benchmarkReporter.ts +++ b/galata/src/benchmarkReporter.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import { JSONObject } from '@lumino/coreutils'; import { chromium, firefox, webkit } from '@playwright/test'; import { @@ -339,6 +344,9 @@ class BenchmarkReporter implements Reporter { this._comparison = options.comparison ?? 'snapshot'; + this._expectedReference = + process.env['BENCHMARK_EXPECTED_REFERENCE'] ?? + benchmark.DEFAULT_EXPECTED_REFERENCE; this._reference = process.env['BENCHMARK_REFERENCE'] ?? benchmark.DEFAULT_REFERENCE; @@ -381,9 +389,9 @@ class BenchmarkReporter implements Reporter { ...result.attachments .filter(a => a.name === benchmark.DEFAULT_NAME_ATTACHMENT) .map(raw => { - const json = (JSON.parse( + const json = JSON.parse( raw.body?.toString() ?? '{}' - ) as any) as benchmark.IRecord; + ) as any as benchmark.IRecord; return { ...json, reference: this._reference }; }) ); @@ -429,7 +437,10 @@ class BenchmarkReporter implements Reporter { if (!hasExpectations || this.config.updateSnapshots === 'all') { expectations = { values: report.values.map(d => { - return { ...d, reference: benchmark.DEFAULT_EXPECTED_REFERENCE }; + return { + ...d, + reference: this._expectedReference + }; }), metadata: report.metadata }; @@ -450,10 +461,8 @@ class BenchmarkReporter implements Reporter { } // - Create report - const [ - reportContentString, - reportExtension - ] = await this._buildTextReport(allData); + const [reportContentString, reportExtension] = + await this._buildTextReport(allData); const reportFile = path.resolve( outputDir, `${baseName}.${reportExtension}` @@ -486,7 +495,7 @@ class BenchmarkReporter implements Reporter { * @param allData all test records. * @param comparison logic of test comparisons: * 'snapshot' or 'project'; default 'snapshot'. - * @return A list of two strings, the first one + * @returns A list of two strings, the first one * is the content of report, the second one is the extension of report file. */ protected async defaultTextReportFactory( @@ -539,10 +548,12 @@ class BenchmarkReporter implements Reporter { } const compare = - (groups.values().next().value?.values().next().value as Map< - string, - Map - >).size === 2; + ( + groups.values().next().value?.values().next().value as Map< + string, + Map + > + ).size === 2; // - Create report const reportContent = new Array( @@ -563,10 +574,13 @@ class BenchmarkReporter implements Reporter { let header = '| Test file |'; let nFiles = 0; - for (const [ - file - ] of groups.values().next().value.values().next().value.values().next() - .value) { + for (const [file] of groups + .values() + .next() + .value.values() + .next() + .value.values() + .next().value) { header += ` ${file} |`; nFiles++; } @@ -574,7 +588,7 @@ class BenchmarkReporter implements Reporter { reportContent.push(new Array(nFiles + 2).fill('|').join(' --- ')); const filler = new Array(nFiles).fill('|').join(' '); - let changeReference = benchmark.DEFAULT_EXPECTED_REFERENCE; + let changeReference = this._expectedReference; for (const [test, testGroup] of groups) { reportContent.push(`| **${test}** | ` + filler); @@ -588,10 +602,7 @@ class BenchmarkReporter implements Reporter { const [q1, median, q3] = vs.quartiles(dataGroup); if (compare) { - if ( - reference === benchmark.DEFAULT_REFERENCE || - !actual.has(filename) - ) { + if (reference === this._reference || !actual.has(filename)) { actual.set(filename, dataGroup); } else { changeReference = reference; @@ -661,7 +672,7 @@ class BenchmarkReporter implements Reporter { * @param allData all test records. * @param comparison logic of test comparisons: * 'snapshot' or 'project'; default 'snapshot'. - * @return VegaLite configuration + * @returns VegaLite configuration */ protected defaultVegaLiteConfigFactory( allData: Array, @@ -729,6 +740,7 @@ class BenchmarkReporter implements Reporter { protected config: FullConfig; protected suite: Suite; private _comparison: 'snapshot' | 'project'; + private _expectedReference: string; private _outputFile: string; private _reference: string; private _report: IReportRecord[]; diff --git a/galata/src/benchmarkVLTpl.ts b/galata/src/benchmarkVLTpl.ts index fcf2eebc3acb..2e2b8c9b2bce 100644 --- a/galata/src/benchmarkVLTpl.ts +++ b/galata/src/benchmarkVLTpl.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + // Vega-Lite configuration /** diff --git a/galata/src/contents.ts b/galata/src/contents.ts index 4a375f3adc69..b3da34960dc8 100644 --- a/galata/src/contents.ts +++ b/galata/src/contents.ts @@ -2,15 +2,12 @@ // Distributed under the terms of the Modified BSD License. import { URLExt } from '@jupyterlab/coreutils'; -import { IDocumentManager } from '@jupyterlab/docmanager'; -import { Contents } from '@jupyterlab/services'; -import { APIRequestContext, APIResponse, Page } from '@playwright/test'; -import fetch, { RequestInit, Response } from 'node-fetch'; +import type { IDocumentManager } from '@jupyterlab/docmanager'; +import type { Contents } from '@jupyterlab/services'; +import type { APIRequestContext, APIResponse, Page } from '@playwright/test'; +import type { ReadStream } from 'fs-extra'; import * as path from 'path'; -import { - IPluginNameToInterfaceMap, - PLUGIN_ID_DOC_MANAGER -} from './inpage/tokens'; +import type { IPluginNameToInterfaceMap } from './extension'; import * as Utils from './utils'; /** @@ -24,22 +21,26 @@ export class ContentsHelper { /** * Construct a new instance of ContentsHelper * - * @param baseURL Server base URL - * @param page Playwright page model object * @param request Playwright API request context + * @param page Playwright page model object */ constructor( - readonly baseURL: string, - readonly page?: Page, - request?: APIRequestContext + request?: APIRequestContext, + readonly page?: Page ) { if (request) { this.request = request; } else if (page) { this.request = page.context().request; + } else { + throw new TypeError( + 'You must provide `request` or `page` to the contents helper.' + ); } } + readonly request: APIRequestContext; + /** * Return the model for a path. * @@ -65,10 +66,7 @@ export class ContentsHelper { console.error(`Fail to get content metadata for ${path}`, error); } - const succeeded = - (typeof response?.status === 'function' - ? response.status() - : response?.status) === 200; + const succeeded = response?.status() === 200; if (succeeded) { return response!.json(); @@ -184,7 +182,7 @@ export class ContentsHelper { try { response = await this._fetch(destinationPath, { method: 'PUT', - body: data + data }); } catch (error) { console.error( @@ -193,10 +191,7 @@ export class ContentsHelper { ); } - const succeeded = - (typeof response?.status === 'function' - ? response.status() - : response?.status) === 201; + const succeeded = response?.status() === 201; if (succeeded) { return await this.fileExists(destinationPath); @@ -244,10 +239,7 @@ export class ContentsHelper { console.error(`Failed to delete file ${filePath}`, error); } - const succeeded = - (typeof response?.status === 'function' - ? response.status() - : response?.status) === 204; + const succeeded = response?.status() === 204; if (succeeded) { return !(await this.fileExists(fileName)); @@ -304,14 +296,15 @@ export class ContentsHelper { // => Use galata in-page if page is available return await this.page.evaluate( async ({ pluginId, oldName, newName }) => { - const docManager = (await window.galataip.getPlugin( + const docManager = (await window.galata.getPlugin( pluginId )) as IDocumentManager; const result = await docManager.rename(oldName, newName); return result !== null; }, { - pluginId: PLUGIN_ID_DOC_MANAGER as keyof IPluginNameToInterfaceMap, + pluginId: + '@jupyterlab/docmanager-extension:manager' as keyof IPluginNameToInterfaceMap, oldName: oldName, newName: newName } @@ -323,16 +316,13 @@ export class ContentsHelper { try { response = await this._fetch(oldName, { method: 'PATCH', - body: JSON.stringify({ path: newName }) + data: JSON.stringify({ path: newName }) }); } catch (error) { console.error(`Failed to rename file ${oldName} to ${newName}`, error); } - const succeeded = - (typeof response?.status === 'function' - ? response.status() - : response?.status) === 200; + const succeeded = response?.status() === 200; if (succeeded) { return await this.fileExists(newName); @@ -373,7 +363,7 @@ export class ContentsHelper { } protected async _createDirectory(dirPath: string): Promise { - const body = JSON.stringify({ + const data = JSON.stringify({ format: 'json', type: 'directory' }); @@ -383,44 +373,103 @@ export class ContentsHelper { try { response = await this._fetch(dirPath, { method: 'PUT', - body + data }); } catch (error) { console.error(`Failed to create directory ${dirPath}`, error); } - return ( - (typeof response?.status === 'function' - ? response.status() - : response?.status) === 201 - ); + return response?.status() === 201; } private async _fetch( path: string, - request: RequestInit = { method: 'GET' } - ): Promise { + options: { + /** + * Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string and + * `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` header will + * be set to `application/octet-stream` if not explicitly set. + */ + data?: string | Buffer; + + /** + * Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status codes. + */ + failOnStatusCode?: boolean; + + /** + * Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent as + * this request body. If this parameter is specified `content-type` header will be set to + * `application/x-www-form-urlencoded` unless explicitly provided. + */ + form?: { [key: string]: string | number | boolean }; + + /** + * Allows to set HTTP headers. + */ + headers?: { [key: string]: string }; + + /** + * Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + */ + ignoreHTTPSErrors?: boolean; + + /** + * If set changes the fetch method (e.g. [PUT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) or + * [POST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)). If not specified, GET method is used. + */ + method?: string; + + /** + * Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this request + * body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless explicitly + * provided. File values can be passed either as [`fs.ReadStream`](https://nodejs.org/api/fs.html#fs_class_fs_readstream) + * or as file-like object containing file name, mime-type and its content. + */ + multipart?: { + [key: string]: + | string + | number + | boolean + | ReadStream + | { + /** + * File name + */ + name: string; + + /** + * File type + */ + mimeType: string; + + /** + * File content + */ + buffer: Buffer; + }; + }; + + /** + * Query parameters to be sent with the URL. + */ + params?: { [key: string]: string | number | boolean }; + + /** + * Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + */ + timeout?: number; + } = { method: 'GET' } + ): Promise { const baseUrl = this.page ? await Utils.getBaseUrl(this.page) : '/'; const token = this.page ? await Utils.getToken(this.page) : ''; let url = URLExt.join(baseUrl, 'api/contents', path); if (token) { - request.headers = { Authorization: `Token ${token}` }; + options.headers = { Authorization: `Token ${token}` }; } - let response: APIResponse | Response | null = null; - - if (this.request) { - response = await this.request.fetch(url, { - ...(request as any), - data: request.body - }); - } else { - response = await fetch(URLExt.join(this.baseURL, url), request); - } - return response; + return this.request.fetch(url, options); } - - readonly request: APIRequestContext | null = null; } diff --git a/galata/src/extension.ts b/galata/src/extension.ts new file mode 100644 index 000000000000..f65e72c7147b --- /dev/null +++ b/galata/src/extension.ts @@ -0,0 +1,283 @@ +// Copyright (c) Jupyter Development Team. +// Copyright (c) Bloomberg Finance LP. +// Distributed under the terms of the Modified BSD License. + +// This export the types (and only the types) from extension/token.ts +// Required for typedoc to be happy otherwise we could have used `from '@jupyterlab/extension/lib/token';` + +import type { JupyterFrontEnd } from '@jupyterlab/application'; +import type { IRouter } from '@jupyterlab/application'; +import type { + Dialog, + Notification, + NotificationManager, + WidgetTracker +} from '@jupyterlab/apputils'; +import type { IDebugger } from '@jupyterlab/debugger'; +import type { IDocumentManager } from '@jupyterlab/docmanager'; +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; + +declare global { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + /** + * Access Jupyter Application object + */ + jupyterapp: JupyterFrontEnd; + /** + * Access to Galata In-Page helpers + * + * Those helpers are injected through a JupyterLab extension + */ + galata: IGalataInpage; + /** + * Access to Galata In-Page helpers + * + * @deprecated since v4 + * Those helpers are injected through a JupyterLab extension + */ + galataip: IGalataInpage; + } +} + +/** + * Static objects exposed. + */ +export interface IGalataHelpers { + /** + * JupyterLab dialogs tracker. + */ + readonly dialogs: WidgetTracker>; + /** + * JupyterLab notifications manager. + */ + readonly notifications: NotificationManager; +} + +/** + * Cell execution callbacks interface + */ +export interface INotebookRunCallback { + /** + * Callback before scrolling to the cell + */ + onBeforeScroll?: () => Promise; + /** + * Callback after scrolling to the cell + */ + onAfterScroll?: () => Promise; + /** + * Callback after cell execution + */ + onAfterCellRun?: (cellIndex: number) => Promise; +} + +/** + * waitForSelector options + */ +export interface IWaitForSelectorOptions { + /** + * Test for the element to be hidden. + */ + hidden?: boolean; +} + +export interface IPluginNameToInterfaceMap { + '@jupyterlab/galata-extension:helpers': IGalataHelpers; + '@jupyterlab/application-extension:router': IRouter; + '@jupyterlab/docmanager-extension:manager': IDocumentManager; + '@jupyterlab/apputils-extension:settings': ISettingRegistry; + '@jupyterlab/debugger-extension:service': IDebugger; +} + +/** + * Galata In-Page interface + */ +export interface IGalataInpage { + /** + * Delete all cells of the active notebook + */ + deleteNotebookCells(): Promise; + + /** + * Get the index of a toolbar item + * + * @param itemName Item name + * @returns Index + */ + getNotebookToolbarItemIndex(itemName: string): number; + + /** + * Get an application plugin + * + * @param pluginId Plugin ID + * @returns Application plugin + */ + getPlugin( + pluginId: K + ): Promise; + + /** + * Get the Jupyter notifications. + * + * @returns Jupyter Notifications + */ + getNotifications(): Promise; + + /** + * Test if one or all cells have an execution number. + * + * @param cellIndex Cell index + * @returns Whether the cell was executed or not + * + * ### Notes + * It checks that no cells have a `null` execution count. + */ + haveBeenExecuted(cellIndex?: number): boolean; + + /** + * Test if a cell is selected in the active notebook + * + * @param cellIndex Cell index + * @returns Whether the cell is selected or not + */ + isNotebookCellSelected(cellIndex: number): boolean; + + /** + * Test if a element is visible or not + * + * @param el Element + * @returns Test result + */ + isElementVisible(el: HTMLElement): boolean; + + /** + * Disconnect a listener to new Jupyter dialog events. + * + * @param event Event type + * @param listener Event listener + */ + off(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + /** + * Disconnect a listener to new or updated Jupyter notification events. + * + * @param event Event type + * @param listener Event listener + */ + off( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + + /** + * Connect a listener to new Jupyter dialog events. + * + * @param event Event type + * @param listener Event listener + */ + on(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + + /** + * Connect a listener to new or updated Jupyter notification events. + * + * @param event Event type + * @param listener Event listener + */ + on( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + + /** + * Connect a listener to the next new Jupyter dialog event. + * + * @param event Event type + * @param listener Event listener + */ + once(event: 'dialog', listener: (dialog: Dialog | null) => void): void; + + /** + * Connect a listener to the next new or updated Jupyter notification event. + * + * @param event Event type + * @param listener Event listener + */ + once( + event: 'notification', + listener: (notification: Notification.INotification) => void + ): void; + + /** + * Save the active notebook + */ + saveActiveNotebook(): Promise; + + /** + * Set the application theme + * + * @param themeName Theme name + */ + setTheme(themeName: string): Promise; + + /** + * Reset execution count of one or all cells. + * + * @param cellIndex Cell index + */ + resetExecutionCount(cellIndex?: number): void; + + /** + * Run the active notebook cell by cell + * and execute the callback after each cell execution + * + * @param callback Callback + */ + runActiveNotebookCellByCell(callback?: INotebookRunCallback): Promise; + + /** + * Wait for the route to be on path and close all documents + * + * @param path Path to monitor + */ + waitForLaunch(path?: string): Promise; + + /** + * Wait for an element to be found from a CSS selector + * + * @param selector CSS selector + * @param node Element + * @param options Options + * @returns Selected element + */ + waitForSelector( + selector: string, + node?: Element, + options?: IWaitForSelectorOptions + ): Promise; + + /** + * Waits for the given `timeout` in milliseconds. + * + * @param timeout A timeout to wait for + */ + waitForTimeout(duration: number): Promise; + + /** + * Wait for an element to be found from a XPath + * + * @param selector CSS selector + * @param node Element + * @param options Options + * @returns Selected element + */ + waitForXPath( + selector: string, + node?: Element, + options?: IWaitForSelectorOptions + ): Promise; + + /** + * Application object + */ + readonly app: JupyterFrontEnd; +} diff --git a/galata/src/fixtures.ts b/galata/src/fixtures.ts index 1b8eafbcda9e..6a153c346ebc 100644 --- a/galata/src/fixtures.ts +++ b/galata/src/fixtures.ts @@ -2,7 +2,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import type { Session, TerminalAPI } from '@jupyterlab/services'; +import type { Session, TerminalAPI, User } from '@jupyterlab/services'; import { test as base, Page, @@ -92,6 +92,17 @@ export type GalataOptions = { * they are still initialized with the hard drive values. */ mockSettings: boolean | Record; + /** + * Mock JupyterLab user in-memory or not. + * + * Possible values are: + * - true (default): JupyterLab user will be mocked on a per test basis + * - false: JupyterLab user won't be mocked (It will be a random user so snapshots won't match) + * - Record: Initial JupyterLab user - Mapping (user attribute, value). + * + * By default the user is stored in-memory. + */ + mockUser: boolean | Partial; /** * Galata can keep the uploaded and created files in ``tmpPath`` on * the server root for debugging purpose. By default the files are @@ -160,7 +171,7 @@ export const test: TestType< * * Default: /lab */ - appPath: '/lab', + appPath: ['/lab', { option: true }], /** * Whether to go to JupyterLab page within the fixture or not. * @@ -168,7 +179,7 @@ export const test: TestType< * * Note: Setting it to false allows to register new route mock-ups for example. */ - autoGoto: true, + autoGoto: [true, { option: true }], /** * Mock JupyterLab config in-memory or not. * @@ -190,7 +201,7 @@ export const test: TestType< * * By default the state is stored in-memory */ - mockState: true, + mockState: [true, { option: true }], /** * Mock JupyterLab settings in-memory or not. * @@ -204,7 +215,18 @@ export const test: TestType< * By default the settings are stored in-memory. However the * they are still initialized with the hard drive values. */ - mockSettings: galata.DEFAULT_SETTINGS, + mockSettings: [galata.DEFAULT_SETTINGS, { option: true }], + /** + * Mock JupyterLab user in-memory or not. + * + * Possible values are: + * - true (default): JupyterLab user will be mocked on a per test basis + * - false: JupyterLab user won't be mocked (It will be a random user so snapshots won't match) + * - Record: Initial JupyterLab user - Mapping (user attribute, value). + * + * By default the user is stored in-memory. + */ + mockUser: [true, { option: true }], /** * Galata can keep the uploaded and created files in ``tmpPath`` on * the server root for debugging purpose. By default the files are @@ -214,7 +236,7 @@ export const test: TestType< * - 'on' - ``tmpPath`` is never deleted * - 'only-on-failure' - ``tmpPath`` is deleted except if a test failed or timed out. */ - serverFiles: 'off', + serverFiles: ['off', { option: true }], /** * Sessions created during the test. * @@ -224,17 +246,13 @@ export const test: TestType< * * By default the sessions created during a test will be tracked and disposed at the end. */ - sessions: async ({ baseURL }, use) => { + sessions: async ({ request }, use) => { const sessions = new Map(); await use(sessions); if (sessions.size > 0) { - await galata.Mock.clearRunners( - baseURL!, - [...sessions.keys()], - 'sessions' - ); + await galata.Mock.clearRunners(request, [...sessions.keys()], 'sessions'); } }, /** @@ -242,18 +260,18 @@ export const test: TestType< * * Possible values are: * - null: The Terminals API won't be mocked - * - Map: The Terminals created during a test. + * - Map: The Terminals created during a test. * * By default the Terminals created during a test will be tracked and disposed at the end. */ - terminals: async ({ baseURL }, use) => { + terminals: async ({ request }, use) => { const terminals = new Map(); await use(terminals); if (terminals.size > 0) { await galata.Mock.clearRunners( - baseURL!, + request, [...terminals.keys()], 'terminals' ); @@ -265,13 +283,13 @@ export const test: TestType< * Note: if you override this string, you will need to take care of creating the * folder and cleaning it. */ - tmpPath: async ({ baseURL, serverFiles, request }, use, testInfo) => { + tmpPath: async ({ request, serverFiles }, use, testInfo) => { // Remove appended retry part for reproducibility const testFolder = path .basename(testInfo.outputDir) .replace(/-retry\d+$/i, ''); - const contents = new ContentsHelper(baseURL!, undefined, request); + const contents = new ContentsHelper(request); if (await contents.directoryExists(testFolder)) { await contents.deleteDirectory(testFolder); @@ -309,7 +327,6 @@ export const test: TestType< await helpers.waitForCondition(() => { return helpers.activity.isTabActive('Launcher'); }); - // Oddly current tab is not always set to active if (!(await helpers.isInSimpleMode())) { await helpers.activity.activateTab('Launcher'); @@ -341,6 +358,7 @@ export const test: TestType< mockConfig, mockSettings, mockState, + mockUser, page, sessions, terminals, @@ -357,6 +375,7 @@ export const test: TestType< mockConfig, mockSettings, mockState, + mockUser, page, sessions, terminals, diff --git a/galata/src/galata.ts b/galata/src/galata.ts index b47d09afc81f..74f6627da178 100644 --- a/galata/src/galata.ts +++ b/galata/src/galata.ts @@ -3,12 +3,17 @@ // Distributed under the terms of the Modified BSD License. import type * as nbformat from '@jupyterlab/nbformat'; -import type { Session, TerminalAPI, Workspace } from '@jupyterlab/services'; +import type { + Session, + TerminalAPI, + User, + Workspace +} from '@jupyterlab/services'; import type { ISettingRegistry } from '@jupyterlab/settingregistry'; import type { JSONObject } from '@lumino/coreutils'; +import { UUID } from '@lumino/coreutils'; import type { APIRequestContext, Browser, Page } from '@playwright/test'; import * as json5 from 'json5'; -import fetch from 'node-fetch'; import { ContentsHelper } from './contents'; import { PerformanceHelper } from './helpers'; import { @@ -30,13 +35,20 @@ export namespace galata { checkForUpdates: false, fetchNews: 'false' }, - '@jupyterlab/fileeditor-extension:plugin': { - editorConfig: { cursorBlinkRate: 0 } - }, - '@jupyterlab/notebook-extension:tracker': { - codeCellConfig: { cursorBlinkRate: 0 }, - markdownCellConfig: { cursorBlinkRate: 0 }, - rawCellConfig: { cursorBlinkRate: 0 } + '@jupyterlab/fileeditor-extension:plugin': {}, + '@jupyterlab/notebook-extension:tracker': {}, + '@jupyterlab/codemirror-extension:plugin': { + defaultConfig: { + cursorBlinkRate: 0 + } + } + }; + + export const DEFAULT_DOCUMENTATION_STATE: Record = { + data: { + 'layout-restorer:data': { + relativeSizes: [0, 1, 0] + } } }; @@ -51,7 +63,6 @@ export namespace galata { export type DefaultSidebarTabId = | 'filebrowser' | 'jp-running-sessions' - | 'tab-manager' | 'jp-property-inspector' | 'table-of-contents' | 'extensionmanager.main-view' @@ -84,6 +95,78 @@ export namespace galata { */ export type NotebookToolbarItemId = DefaultNotebookToolbarItemId | string; + /** + * Options to create a new page + */ + export interface INewPageOption { + /** + * Application base URL + */ + baseURL: string; + /** + * Playwright browser model + */ + browser: Browser; + /** + * Callback that resolved when the application page is ready + */ + waitForApplication: (page: Page, helpers: IJupyterLabPage) => Promise; + /** + * Application URL path fragment + * + * Default: /lab + */ + appPath?: string; + /** + * Whether to go to JupyterLab page within the fixture or not. + * + * Default: true + */ + autoGoto?: boolean; + /** + * Mock Jupyter Server configuration in-memory or not. + * + * Default true + */ + mockConfig?: boolean | Record; + /** + * Mock JupyterLab state in-memory or not. + * + * Default galata.DEFAULT_SETTINGS + */ + mockSettings?: boolean | Record; + /** + * Mock JupyterLab settings in-memory or not. + * + * Default true + */ + mockState?: boolean | Record; + /** + * Mock JupyterLab user in-memory or not. + * + * Default true + */ + mockUser?: boolean | Partial; + /** + * Whether to store sessions in memory or not. + * + * Default true + */ + mockSessions?: boolean; + /** + * Whether to store terminals in memory or not. + * + * Default true + */ + mockTerminals?: boolean; + /** + * Create and delete a temporary path during the page existence + * + * Default '' + */ + tmpPath?: string; + } + /** * Add the Galata helpers to the page model * @@ -125,6 +208,7 @@ export namespace galata { mockConfig: boolean | Record, mockSettings: boolean | Record, mockState: boolean | Record, + mockUser: boolean | Partial, page: Page, sessions: Map | null, terminals: Map | null, @@ -168,6 +252,24 @@ export namespace galata { await Mock.mockState(page, workspace); } + let user: User.IUser = { + identity: { + username: UUID.uuid4(), + name: 'jovyan', + display_name: 'jovyan', + initials: 'JP', + color: 'var(--jp-collaborator-color1)' + }, + permissions: {} + }; + if (mockUser) { + if (typeof mockUser !== 'boolean') { + user = { ...mockUser } as any; + } + // The user will be stored in-memory + await Mock.mockUser(page, user); + } + // Add sessions and terminals trackers if (sessions) { await Mock.mockRunners(page, sessions, 'sessions'); @@ -187,57 +289,78 @@ export namespace galata { /** * Create a contents REST API helpers object * - * @param baseURL Application base URL - * @param page Playwright page model * @param request Playwright API request context + * @param page Playwright page model * @returns Contents REST API helpers */ export function newContentsHelper( - baseURL: string, - page?: Page, - request?: APIRequestContext + request?: APIRequestContext, + page?: Page ): ContentsHelper { - return new ContentsHelper(baseURL, page, request); + return new ContentsHelper(request, page); } /** - * Create a page with Galata helpers for the given browser + * Create a page with Galata helpers for the given browser in a new context. * - * @param browser Playwright browser model - * @param baseURL Application base URL - * @param waitForApplication Callback that resolved when the application page is ready - * @param appPath Application URL path fragment * @returns Playwright page model with Galata helpers */ - export async function newPage( - appPath: string, - autoGoto: boolean, - baseURL: string, - browser: Browser, - mockConfig: boolean | Record, - mockSettings: boolean | Record, - mockState: boolean | Record, - sessions: Map | null, - terminals: Map | null, - tmpPath: string, - waitForApplication: (page: Page, helpers: IJupyterLabPage) => Promise - ): Promise { - const context = await browser.newContext(); - const page = await context.newPage(); - - return initTestPage( + export async function newPage(options: INewPageOption): Promise<{ + page: IJupyterLabPageFixture; + sessions: Map | null; + terminals: Map | null; + }> { + const { appPath, autoGoto, baseURL, + browser, + waitForApplication, mockConfig, + mockSessions, mockSettings, mockState, - page, + mockTerminals, + mockUser, + tmpPath + } = { + appPath: '/lab', + autoGoto: true, + mockConfig: true, + mockSessions: true, + mockSettings: galata.DEFAULT_SETTINGS, + mockState: true, + mockTerminals: true, + mockUser: true, + tmpPath: '', + ...options + }; + const context = await browser.newContext(); + const page = await context.newPage(); + + const sessions = mockSessions ? new Map() : null; + const terminals = mockTerminals + ? new Map() + : null; + + return { + page: await initTestPage( + appPath, + autoGoto, + baseURL, + mockConfig, + mockSettings, + mockState, + mockUser, + page, + sessions, + terminals, + tmpPath, + waitForApplication + ), sessions, - terminals, - tmpPath, - waitForApplication - ); + terminals + }; } /** @@ -281,7 +404,7 @@ export namespace galata { * * The session id can be found in the named group `id`. * - * The id will be suffixed by '/'. + * The id will be prefixed by '/'. */ export const sessions = /.*\/api\/sessions(?\/[@:-\w]+)?/; @@ -290,7 +413,7 @@ export namespace galata { * * The schema name can be found in the named group `id`. * - * The id will be suffixed by '/'. + * The id will be prefixed by '/'. */ export const settings = /.*\/api\/settings(?(\/[@:-\w]+)*)/; @@ -299,7 +422,7 @@ export namespace galata { * * The terminal id can be found in the named group `id`. * - * The id will be suffixed by '/'. + * The id will be prefixed by '/'. */ export const terminals = /.*\/api\/terminals(?\/[@:-\w]+)?/; @@ -308,7 +431,7 @@ export namespace galata { * * The locale can be found in the named group `id`. * - * The id will be suffixed by '/'. + * The id will be prefixed by '/'. */ export const translations = /.*\/api\/translations(?\/[@:-\w]+)?/; @@ -317,9 +440,14 @@ export namespace galata { * * The space name can be found in the named group `id`. * - * The id will be suffixed by '/'. + * The id will be prefixed by '/'. */ export const workspaces = /.*\/api\/workspaces(?(\/[-\w]+)+)/; + + /** + * User API + */ + export const user = /.*\/api\/me.*/; } /** @@ -433,6 +561,69 @@ export namespace galata { * Mock methods */ export namespace Mock { + /** + * Set last modified attributes one day ago one listing + * directory content. + * + * @param page Page model object + * + * #### Notes + * The goal is to freeze the file browser display + */ + export async function freezeContentLastModified(page: Page): Promise { + // Listen for closing connection (may happen when request are still being processed) + let isClosed = false; + const ctxt = page.context(); + ctxt.once('close', () => { + isClosed = true; + }); + ctxt.browser()?.once('disconnected', () => { + isClosed = true; + }); + + return page.route(Routes.contents, async (route, request) => { + switch (request.method()) { + case 'GET': { + // Proxy the GET request + const response = await ctxt.request.fetch(request); + if (!response.ok()) { + if (!page.isClosed() && !isClosed) { + return route.fulfill({ + status: response.status(), + body: await response.text() + }); + } + break; + } + const data = await response.json(); + // Modify the last_modified values to be set one day before now. + if ( + data['type'] === 'directory' && + Array.isArray(data['content']) + ) { + const now = Date.now(); + const aDayAgo = new Date(now - 24 * 3600 * 1000).toISOString(); + for (const entry of data['content'] as any[]) { + // Mutate the list in-place + entry['last_modified'] = aDayAgo; + } + } + + if (!page.isClosed() && !isClosed) { + return route.fulfill({ + status: 200, + body: JSON.stringify(data), + contentType: 'application/json' + }); + } + break; + } + default: + return route.continue(); + } + }); + } + /** * Clear all wanted sessions or terminals. * @@ -443,25 +634,18 @@ export namespace galata { * @returns Whether the runners were closed or not */ export async function clearRunners( - baseURL: string, + request: APIRequestContext, runners: string[], - type: 'sessions' | 'terminals', - request?: APIRequestContext + type: 'sessions' | 'terminals' ): Promise { const responses = await Promise.all( [...new Set(runners)].map(id => - request - ? (request.fetch(`/api/${type}/${id}`, { - method: 'DELETE' - }) as any) - : (fetch(`${baseURL}/api/${type}/${id}`, { - method: 'DELETE' - }) as any) + request.fetch(`/api/${type}/${id}`, { + method: 'DELETE' + }) ) ); - return responses.every(response => - typeof response.ok === 'function' ? response.ok() : response.ok - ); + return responses.every(response => response.ok()); } /** @@ -522,10 +706,10 @@ export namespace galata { // Listen for closing connection (may happen when request are still being processed) let isClosed = false; const ctxt = page.context(); - ctxt.on('close', () => { + ctxt.once('close', () => { isClosed = true; }); - ctxt.browser()?.on('disconnected', () => { + ctxt.browser()?.once('disconnected', () => { isClosed = true; }); return page.route(routeRegex, async (route, request) => { @@ -725,10 +909,10 @@ export namespace galata { // Listen for closing connection (may happen when request are still being processed) let isClosed = false; const ctxt = page.context(); - ctxt.on('close', () => { + ctxt.once('close', () => { isClosed = true; }); - ctxt.browser()?.on('disconnected', () => { + ctxt.browser()?.once('disconnected', () => { isClosed = true; }); @@ -827,5 +1011,25 @@ export namespace galata { } }); } + + /** + * Mock user route. + * + * @param page Page model object + * @param user In-memory user + */ + export function mockUser(page: Page, user: User.IUser): Promise { + return page.route(Routes.user, (route, request) => { + switch (request.method()) { + case 'GET': + return route.fulfill({ + status: 200, + body: JSON.stringify(user) + }); + default: + return route.continue(); + } + }); + } } } diff --git a/galata/src/helpers/activity.ts b/galata/src/helpers/activity.ts index d8739d00e44e..5a5760ff8f25 100644 --- a/galata/src/helpers/activity.ts +++ b/galata/src/helpers/activity.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { ElementHandle, Page } from '@playwright/test'; +import { ElementHandle, Locator, Page } from '@playwright/test'; import * as Utils from '../utils'; /** @@ -12,21 +12,28 @@ export class ActivityHelper { /** * JupyterLab launcher selector + * + * @deprecated You should use locator selector {@link launcher} */ get launcherSelector(): string { return Utils.xpBuildActivityTabSelector('Launcher'); } + /** + * JupyterLab launcher tab + */ + get launcher(): Locator { + return this.page.getByRole('main').getByRole('tab', { name: 'Launcher' }); + } + /** * Close all widgets in the main area */ async closeAll(): Promise { - await this.page.evaluate(async (launcherSelector: string) => { - const app = window.jupyterlab ?? window.jupyterapp; - - await app.commands.execute('application:close-all'); - await window.galataip.waitForXPath(launcherSelector); - }, this.launcherSelector); + await this.page.evaluate(async () => { + await window.jupyterapp.commands.execute('application:close-all'); + }); + await this.launcher.waitFor(); } /** @@ -36,14 +43,22 @@ export class ActivityHelper { * @returns Active status */ async isTabActive(name: string): Promise { - const tab = await this.getTab(name); - return ( - (tab && - (await tab.evaluate((tab: Element) => - tab.classList.contains('lm-mod-current') - ))) ?? - false - ); + if (await Utils.isInSimpleMode(this.page)) { + const activeTab = await this.page + .locator('#jp-title-panel-title') + .getByRole('textbox') + .inputValue(); + return activeTab === name; + } else { + const tab = await this.getTab(name); + return ( + (tab && + (await tab.evaluate((tab: Element) => + tab.classList.contains('jp-mod-current') + ))) ?? + false + ); + } } /** @@ -52,12 +67,25 @@ export class ActivityHelper { * @param name Activity name * @returns Handle on the tab or null if the tab is not found */ - getTab(name?: string): Promise | null> { - const page = this.page; - const tabSelector = name - ? Utils.xpBuildActivityTabSelector(name) - : Utils.xpBuildActiveActivityTabSelector(); - return page.$(`xpath=${tabSelector}`); + async getTab(name?: string): Promise | null> { + let handle: ElementHandle | null = null; + try { + handle = await this.getTabLocator(name).elementHandle({ timeout: 500 }); + } catch { + handle = null; + } + return handle; + } + + /** + * Get a tab locator + * @param name Activity name + * @returns Tab locator + */ + getTabLocator(name?: string): Locator { + return name + ? this.page.getByRole('main').getByRole('tab', { name }) + : this.page.getByRole('main').locator('.jp-mod-current[role="tab"]'); } /** @@ -68,15 +96,51 @@ export class ActivityHelper { */ async getPanel(name?: string): Promise | null> { const page = this.page; - const tab = await this.getTab(name); - if (tab) { - const id = await tab.evaluate((tab: Element) => + let locator: Locator; + if (name) { + locator = page.getByRole('main').getByRole('tabpanel', { name }); + } else { + const activeTab = await this.getTab(); + const id = await activeTab?.evaluate((tab: Element) => tab.getAttribute('data-id') ); - return await page.$(`xpath=${Utils.xpBuildActivityPanelSelector(id!)}`); + if (!id) { + return null; + } + locator = page.getByRole('main').locator(`[role="tabpanel"][id="${id}"]`); + } + + let handle: ElementHandle | null = null; + try { + handle = await locator.elementHandle({ timeout: 500 }); + } catch { + handle = null; + } + + return handle; + } + + /** + * Get a panel locator + * + * @param name Activity name + * @returns Panel locator or null + */ + async getPanelLocator(name?: string): Promise { + let locator: Locator; + if (name) { + locator = this.page.getByRole('main').getByRole('tabpanel', { name }); + } else { + const id = await this.getTabLocator().getAttribute('data-id'); + if (!id) { + return null; + } + locator = this.page + .getByRole('main') + .locator(`[role="tabpanel"][id="${id}"]`); } - return null; + return locator; } /** @@ -86,12 +150,10 @@ export class ActivityHelper { */ async closePanel(name: string): Promise { await this.activateTab(name); - await this.page.evaluate(async (launcherSelector: string) => { - const app = window.jupyterlab ?? window.jupyterapp; - - await app.commands.execute('application:close'); - await window.galataip.waitForXPath(launcherSelector); - }, this.launcherSelector); + await this.page.evaluate(async () => { + await window.jupyterapp.commands.execute('application:close'); + }); + await this.launcher.waitFor(); } /** @@ -106,7 +168,7 @@ export class ActivityHelper { await tab.click(); await this.page.waitForFunction( ({ tab }) => { - return tab.classList.contains('jp-mod-current'); + return tab.ariaSelected === 'true'; }, { tab } ); diff --git a/galata/src/helpers/debuggerpanel.ts b/galata/src/helpers/debuggerpanel.ts new file mode 100644 index 000000000000..a12e27fca7d9 --- /dev/null +++ b/galata/src/helpers/debuggerpanel.ts @@ -0,0 +1,159 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { ElementHandle, Page } from '@playwright/test'; +import { SidebarHelper } from './sidebar'; +import { NotebookHelper } from './notebook'; +import { waitForCondition } from '../utils'; + +const DEBUGGER_ITEM = 'debugger-icon'; + +/** + * Debugger Helper + */ +export class DebuggerHelper { + constructor( + readonly page: Page, + readonly sidebar: SidebarHelper, + readonly notebook: NotebookHelper + ) {} + + /** + * Returns true if debugger toolbar item is enabled, false otherwise + */ + async isOn(): Promise { + if (!(await this.notebook.isAnyActive())) { + return false; + } + const item = await this.notebook.getToolbarItem(DEBUGGER_ITEM); + if (item) { + const button = await item.$('button'); + if (button) { + return (await button.getAttribute('aria-pressed')) === 'true'; + } + } + return false; + } + + /** + * Enables the debugger toolbar item + */ + async switchOn(): Promise { + await waitForCondition(async () => { + const item = await this.notebook.getToolbarItem(DEBUGGER_ITEM); + if (item) { + const button = await item.$('button'); + if (button) { + return (await button.getAttribute('aria-disabled')) !== 'true'; + } + } + return false; + }, 2000); + if (!(await this.isOn())) { + await this.notebook.clickToolbarItem(DEBUGGER_ITEM); + } + } + + /** + * Disables the debugger toolbar item + */ + async switchOff(): Promise { + if (await this.isOn()) { + await this.notebook.clickToolbarItem(DEBUGGER_ITEM); + } + } + + /** + * Returns true if debugger panel is open, false otherwise + */ + async isOpen(): Promise { + return await this.sidebar.isTabOpen('jp-debugger-sidebar'); + } + + /** + * Returns handle to the variables panel content + */ + async getVariablesPanel(): Promise | null> { + return this._getPanel('.jp-DebuggerVariables'); + } + + /** + * Waits for variables to be populated in the variables panel + */ + async waitForVariables(): Promise { + await this.page.waitForSelector('.jp-DebuggerVariables-body ul'); + } + + /** + * render variable + */ + async renderVariable(name: string): Promise { + await this.page + .locator(`.jp-DebuggerVariables :text("${name}")`) + .click({ button: 'right' }); + await this.page + .locator('.lm-Menu-itemLabel:text("Render Variable")') + .click(); + await this.page.waitForSelector('.jp-VariableRendererPanel-renderer'); + } + + /** + * Returns handle to callstack panel content + */ + async getCallStackPanel(): Promise | null> { + return this._getPanel('.jp-DebuggerCallstack'); + } + + /** + * Waits for the callstack body to populate in the callstack panel + */ + async waitForCallStack(): Promise { + await this.page.waitForSelector( + '.jp-DebuggerCallstack-body >> .jp-DebuggerCallstackFrame' + ); + } + + /** + * Returns handle to breakpoints panel content + */ + async getBreakPointsPanel(): Promise | null> { + return this._getPanel('.jp-DebuggerBreakpoints'); + } + + /** + * Waits for the breakpoints to appear in the breakpoints panel + */ + async waitForBreakPoints(): Promise { + await this.page.waitForSelector( + '.jp-DebuggerBreakpoints >> .jp-DebuggerBreakpoint' + ); + } + + /** + * Returns handle to sources panel content + */ + async getSourcePanel(): Promise | null> { + return this._getPanel('.jp-DebuggerSources'); + } + + /** + * Waits for sources to be populated in the sources panel + */ + async waitForSources(): Promise { + await this.page.waitForSelector('.jp-DebuggerSources-body >> .jp-Editor', { + state: 'visible' + }); + } + + private async _getPanel( + selector: string + ): Promise | null> { + const panel = await this.sidebar.getContentPanel('right'); + if (panel) { + return panel.$(selector); + } + return null; + } +} diff --git a/galata/src/helpers/filebrowser.ts b/galata/src/helpers/filebrowser.ts index d877011a580d..16237ac3275f 100644 --- a/galata/src/helpers/filebrowser.ts +++ b/galata/src/helpers/filebrowser.ts @@ -10,7 +10,10 @@ import * as Utils from '../utils'; * File Browser Helpers */ export class FileBrowserHelper { - constructor(readonly page: Page, readonly contents: ContentsHelper) {} + constructor( + readonly page: Page, + readonly contents: ContentsHelper + ) {} /** * Create the selector for a file in the file browser @@ -95,10 +98,11 @@ export class FileBrowserHelper { * Note: This will double click on the file; * an editor needs to be available for the given file type. * - * @param filePath Notebook path + * @param filePath File path + * @param factory Document factory to use * @returns Action success status */ - async open(filePath: string): Promise { + async open(filePath: string, factory?: string): Promise { await this.revealFileInBrowser(filePath); const name = path.basename(filePath); @@ -106,10 +110,28 @@ export class FileBrowserHelper { `xpath=${this.xpBuildFileSelector(name)}` ); if (fileItem) { - await fileItem.click({ clickCount: 2 }); - await this.page.waitForSelector(Utils.xpBuildActivityTabSelector(name), { - state: 'visible' - }); + if (factory) { + await fileItem.click({ button: 'right' }); + await this.page + .getByRole('listitem') + .filter({ hasText: 'Open With' }) + .click(); + await this.page + .getByRole('menuitem', { name: factory, exact: true }) + .click(); + } else { + await fileItem.dblclick(); + } + // Use `last` as if a file is already open, it will simply be activated + // if not it will be opened with optionally another factory (but we don't have a way + // to know that from the DOM). + await this.page + .getByRole('main') + .getByRole('tab', { name }) + .last() + .waitFor({ + state: 'visible' + }); } else { return false; } @@ -136,6 +158,7 @@ export class FileBrowserHelper { '.jp-FileBrowser .jp-FileBrowser-crumbs span' ); return ( + // The home is the root if no preferred dir is defined. spans.length === 2 && spans[0].classList.contains('jp-BreadCrumbs-home') ); }); diff --git a/galata/src/helpers/index.ts b/galata/src/helpers/index.ts index 67b014bc64ce..93e716f266a4 100644 --- a/galata/src/helpers/index.ts +++ b/galata/src/helpers/index.ts @@ -10,4 +10,6 @@ export * from './notebook'; export * from './performance'; export * from './sidebar'; export * from './statusbar'; +export * from './style'; export * from './theme'; +export * from './debuggerpanel'; diff --git a/galata/src/helpers/kernel.ts b/galata/src/helpers/kernel.ts index b00f59ac6c3f..b5c1a52f3a2a 100644 --- a/galata/src/helpers/kernel.ts +++ b/galata/src/helpers/kernel.ts @@ -20,8 +20,7 @@ export class KernelHelper { */ async isAnyRunning(): Promise { return await this.page.evaluate(() => { - const app = window.jupyterlab ?? window.jupyterapp; - return app.serviceManager.sessions.running().next() !== undefined; + return !window.jupyterapp.serviceManager.sessions.running().next().done; }); } @@ -30,8 +29,7 @@ export class KernelHelper { */ async shutdownAll(): Promise { await this.page.evaluate(async () => { - const app = window.jupyterlab ?? window.jupyterapp; - await app.serviceManager.sessions.shutdownAll(); + await window.jupyterapp.serviceManager.sessions.shutdownAll(); }); await Utils.waitForCondition(async () => { diff --git a/galata/src/helpers/menu.ts b/galata/src/helpers/menu.ts index d2796529acea..ae87903e3480 100644 --- a/galata/src/helpers/menu.ts +++ b/galata/src/helpers/menu.ts @@ -21,9 +21,12 @@ export class MenuHelper { for (let i = 0; i < numOpenMenus; ++i) { await page.keyboard.press('Escape'); await page.waitForTimeout(100); - await page.waitForFunction((menuCount: number) => { - return document.querySelectorAll('.lm-Menu').length === menuCount; - }, numOpenMenus - (i + 1)); + await page.waitForFunction( + (menuCount: number) => { + return document.querySelectorAll('.lm-Menu').length === menuCount; + }, + numOpenMenus - (i + 1) + ); } } @@ -41,6 +44,21 @@ export class MenuHelper { ); } + /** + * Open a context menu and get its handle. + * + * @param selector Element over which the menu should be opened + * @returns Handle to the menu or null + */ + async openContextMenu( + selector: string + ): Promise | null> { + await this.page.click(selector, { + button: 'right' + }); + return await this.page.$('.lm-Menu'); + } + /** * Get the handle on a menu item from its path. * diff --git a/galata/src/helpers/notebook.ts b/galata/src/helpers/notebook.ts index 8a87e9cbf714..b8fe1df63864 100644 --- a/galata/src/helpers/notebook.ts +++ b/galata/src/helpers/notebook.ts @@ -1,18 +1,23 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import * as nbformat from '@jupyterlab/nbformat'; -import { NotebookPanel } from '@jupyterlab/notebook'; +import type * as nbformat from '@jupyterlab/nbformat'; +import type { NotebookPanel } from '@jupyterlab/notebook'; import { ElementHandle, Page } from '@playwright/test'; import * as path from 'path'; +import { ContentsHelper } from '../contents'; +import type { INotebookRunCallback } from '../extension'; import { galata } from '../galata'; -import { INotebookRunCallback } from '../inpage/tokens'; import * as Utils from '../utils'; import { ActivityHelper } from './activity'; -import { ContentsHelper } from '../contents'; import { FileBrowserHelper } from './filebrowser'; import { MenuHelper } from './menu'; +/** + * Maximal number of retries to get a cell + */ +const MAX_RETRIES = 3; + /** * Notebook helpers */ @@ -116,7 +121,7 @@ export class NotebookHelper { const nbPanel = await this.activity.getPanel(name); if (nbPanel) { - return await nbPanel.$('.jp-NotebookPanel-toolbar'); + return await nbPanel.$('.jp-Toolbar'); } return null; @@ -164,7 +169,7 @@ export class NotebookHelper { if (toolbar) { const itemIndex = await this.page.evaluate(async (itemId: string) => { - return window.galataip.getNotebookToolbarItemIndex(itemId); + return window.galata.getNotebookToolbarItemIndex(itemId); }, itemId); return this.getToolbarItemByIndex(itemIndex); @@ -204,12 +209,12 @@ export class NotebookHelper { async activate(name: string): Promise { if (await this.activity.activateTab(name)) { await this.page.evaluate(async () => { - const galataip = window.galataip; - const nbPanel = galataip.app.shell.currentWidget as NotebookPanel; + const galata = window.galata; + const nbPanel = galata.app.shell.currentWidget as NotebookPanel; await nbPanel.sessionContext.ready; // Assuming that if the session is ready, the kernel is ready also for now and commenting out this line // await nbPanel.session.kernel.ready; - galataip.app.shell.activateById(nbPanel.id); + galata.app.shell.activateById(nbPanel.id); }); return true; @@ -229,7 +234,7 @@ export class NotebookHelper { } await this.page.evaluate(async () => { - await window.galataip.saveActiveNotebook(); + await window.galata.saveActiveNotebook(); }); return true; @@ -246,7 +251,7 @@ export class NotebookHelper { } await this.page.evaluate(async () => { - const app = window.galataip.app; + const app = window.galata.app; const nbPanel = app.shell.currentWidget as NotebookPanel; await nbPanel.context.revert(); }); @@ -264,6 +269,9 @@ export class NotebookHelper { return false; } + await this.page.evaluate(() => { + window.galata.resetExecutionCount(); + }); await this.menu.clickMenuItem('Run>Run All Cells'); await this.waitForRun(); @@ -334,19 +342,56 @@ export class NotebookHelper { } } as INotebookRunCallback); - await window.galataip.runActiveNotebookCellByCell(callbacks); + await window.galata.runActiveNotebookCellByCell(callbacks); }, callbackName); return true; } + /** + * Trust the active notebook + * + * @returns Whether the action succeeded or not. + */ + async trust(): Promise { + if ( + (await this.isAnyActive()) && + (await this.page + .locator('[data-icon="ui-components:not-trusted"]') + .count()) === 1 + ) { + await this.page.keyboard.press('Control+Shift+C'); + await this.page.getByPlaceholder('SEARCH', { exact: true }).fill('trust'); + await this.page.getByText('Trust Notebook').click(); + await this.page.getByRole('button', { name: 'Trust' }).click(); + + return ( + (await this.page + .locator('[data-icon="ui-components:trusted"]') + .count()) === 1 + ); + } + + return true; + } + /** * Wait for notebook cells execution to finish + * + * @param cellIndex Cell index */ - async waitForRun(): Promise { - await this.page.evaluate(async () => { - await window.galataip.waitForNotebookRun(); - }); + async waitForRun(cellIndex?: number): Promise { + const idleLocator = this.page.locator('#jp-main-statusbar >> text=Idle'); + await idleLocator.waitFor(); + + // Wait for all cells to have an execution count + let done = false; + do { + await this.page.waitForTimeout(20); + done = await this.page.evaluate(cellIdx => { + return window.galata.haveBeenExecuted(cellIdx); + }, cellIndex); + } while (!done); } /** @@ -409,9 +454,37 @@ export class NotebookHelper { return -1; } - const cells = await notebook.$$('div.jp-Cell'); + const scrollTop = await notebook.evaluate(node => node.scrollTop); + + // Scroll to bottom + let previousScrollHeight = scrollTop; + let scrollHeight = + previousScrollHeight + + (await notebook.evaluate(node => node.clientHeight)); + do { + await notebook.evaluate((node, scrollTarget) => { + node.scrollTo({ top: scrollTarget }); + }, scrollHeight); + await this.page.waitForTimeout(50); + previousScrollHeight = scrollHeight; + scrollHeight = await notebook.evaluate( + node => node.scrollHeight - node.clientHeight + ); + } while (scrollHeight > previousScrollHeight); + + const lastCell = await notebook.$$('div.jp-Cell >> nth=-1'); + const count = + parseInt( + (await lastCell[0].getAttribute('data-windowed-list-index')) ?? '0', + 10 + ) + 1; + + // Scroll back to original position + await notebook.evaluate((node, scrollTarget) => { + node.scrollTo({ top: scrollTarget }); + }, scrollTop); - return cells.length; + return count; }; /** @@ -426,13 +499,94 @@ export class NotebookHelper { return null; } - const cells = await notebook.$$('div.jp-Cell'); + const allCells = await notebook.$$('div.jp-Cell'); + const filters = await Promise.all(allCells.map(c => c.isVisible())); + const cells = allCells.filter((c, i) => filters[i]); - if (cellIndex < 0 || cellIndex >= cells.length) { - return null; + const firstCell = cells[0]; + const lastCell = cells[cells.length - 1]; + + let firstIndex = parseInt( + (await firstCell.getAttribute('data-windowed-list-index')) ?? '0', + 10 + ); + let lastIndex = parseInt( + (await lastCell.getAttribute('data-windowed-list-index')) ?? '0', + 10 + ); + + if (cellIndex < firstIndex) { + // Scroll up + let scrollTop = + (await firstCell.boundingBox())?.y ?? + (await notebook.evaluate(node => node.scrollTop - node.clientHeight)); + + do { + await notebook.evaluate((node, scrollTarget) => { + node.scrollTo({ top: scrollTarget }); + }, scrollTop); + await this.page.waitForTimeout(50); + + const cells = await notebook.$$('div.jp-Cell'); + const isVisible = await Promise.all(cells.map(c => c.isVisible())); + const firstCell = isVisible.findIndex(visibility => visibility); + + firstIndex = parseInt( + (await cells[firstCell].getAttribute('data-windowed-list-index')) ?? + '0', + 10 + ); + scrollTop = + (await cells[firstCell].boundingBox())?.y ?? + (await notebook.evaluate(node => node.scrollTop - node.clientHeight)); + } while (scrollTop > 0 && firstIndex > cellIndex); + } else if (cellIndex > lastIndex) { + const clientHeight = await notebook.evaluate(node => node.clientHeight); + // Scroll down + const viewport = await ( + await notebook.$$('.jp-WindowedPanel-window') + )[0].boundingBox(); + let scrollHeight = viewport!.y + viewport!.height; + let previousScrollHeight = 0; + + do { + previousScrollHeight = scrollHeight; + await notebook.evaluate((node, scrollTarget) => { + node.scrollTo({ top: scrollTarget }); + }, scrollHeight); + await this.page.waitForTimeout(50); + + const cells = await notebook.$$('div.jp-Cell'); + const isVisible = await Promise.all(cells.map(c => c.isVisible())); + const lastCell = isVisible.lastIndexOf(true); + + lastIndex = parseInt( + (await cells[lastCell].getAttribute('data-windowed-list-index')) ?? + '0', + 10 + ); + + const viewport = await ( + await notebook.$$('.jp-WindowedPanel-window') + )[0].boundingBox(); + scrollHeight = viewport!.y + viewport!.height; + // Avoid jitter + scrollHeight = Math.max( + previousScrollHeight + clientHeight, + scrollHeight + ); + } while (scrollHeight > previousScrollHeight && lastIndex < cellIndex); } - return cells[cellIndex]; + if (firstIndex <= cellIndex && cellIndex <= lastIndex) { + return ( + await notebook.$$( + `div.jp-Cell[data-windowed-list-index="${cellIndex}"]` + ) + )[0]; + } else { + return null; + } } /** @@ -704,6 +858,117 @@ export class NotebookHelper { return false; } + /** + * Clicks a cell gutter line for code cells + * + * @param cellIndex Cell index + * @param lineNumber Cell line number, starts at 1 + */ + async clickCellGutter( + cellIndex: number, + lineNumber: number + ): Promise { + if (lineNumber < 1) { + return false; + } + + if (!(await this.isCellGutterPresent(cellIndex))) { + return false; + } + + const cell = await this.getCell(cellIndex); + const gutters = await cell!.$$( + '.cm-gutters > .cm-gutter.cm-breakpoint-gutter > .cm-gutterElement' + ); + if (gutters.length < lineNumber) { + return false; + } + await gutters[lineNumber].click(); + return true; + } + + /** + * Check if cell gutter is present + * + * @param cellIndex + */ + async isCellGutterPresent(cellIndex: number): Promise { + const cell = await this.getCell(cellIndex); + if (!cell) { + return false; + } + return (await cell.$('.cm-gutters')) !== null; + } + + /** + * Wait until cell gutter is visible + * + * @param cellIndex + */ + async waitForCellGutter(cellIndex: number): Promise { + const cell = await this.getCell(cellIndex); + if (cell) { + await this.page.waitForSelector('.cm-gutters', { + state: 'attached' + }); + } + } + + /** + * Clicks a code gutter line for scripts + * + * @param lineNumber Cell line number, starts at 1 + */ + async clickCodeGutter(lineNumber: number): Promise { + if (lineNumber < 1) { + return false; + } + + if (!(await this.isCodeGutterPresent())) { + return false; + } + + const panel = await this.activity.getPanel(); + await panel!.waitForSelector( + '.cm-gutters > .cm-gutter.cm-breakpoint-gutter > .cm-gutterElement', + { state: 'attached' } + ); + const gutters = await panel!.$$( + '.cm-gutters > .cm-gutter.cm-breakpoint-gutter > .cm-gutterElement' + ); + if (gutters.length < lineNumber) { + return false; + } + await gutters[lineNumber].click(); + return true; + } + + /** + * Check if code gutter is present + * + */ + async isCodeGutterPresent(): Promise { + const panel = await this.activity.getPanel(); + if (!panel) { + return false; + } + return (await panel.$('.cm-gutters')) !== null; + } + + /** + * Wait until cell gutter is visible + * + * @param cellIndex + */ + async waitForCodeGutter(): Promise { + const panel = await this.activity.getPanel(); + if (panel) { + await this.page.waitForSelector('.cm-gutters', { + state: 'attached' + }); + } + } + /** * Select cells * @@ -741,7 +1006,7 @@ export class NotebookHelper { */ async isCellSelected(cellIndex: number): Promise { return await this.page.evaluate((cellIndex: number) => { - return window.galataip.isNotebookCellSelected(cellIndex); + return window.galata.isNotebookCellSelected(cellIndex); }, cellIndex); } @@ -756,7 +1021,7 @@ export class NotebookHelper { } await this.page.evaluate(() => { - return window.galataip.deleteNotebookCells(); + return window.galata.deleteNotebookCells(); }); return true; @@ -778,11 +1043,9 @@ export class NotebookHelper { await this.selectCells(numCells - 1); await this.clickToolbarItem('insert'); - await Utils.waitForCondition( - async (): Promise => { - return (await this.getCellCount()) === numCells + 1; - } - ); + await Utils.waitForCondition(async (): Promise => { + return (await this.getCellCount()) === numCells + 1; + }); return await this.setCell(numCells, cellType, source); } @@ -864,6 +1127,14 @@ export class NotebookHelper { await selectInput.selectOption(cellType); + // Wait for the new cell to be rendered + let cell: ElementHandle | null; + let counter = 1; + do { + await this.page.waitForTimeout(50); + cell = await this.getCell(cellIndex); + } while (cell === null && counter++ < MAX_RETRIES); + return true; } @@ -878,14 +1149,13 @@ export class NotebookHelper { if (!notebook) { return null; } - const cells = await notebook.$$('div.jp-Cell'); - if (cellIndex < 0 || cellIndex >= cells.length) { + const cell = await this.getCell(cellIndex); + + if (!cell) { return null; } - const cell = cells[cellIndex]; - const classList = await Utils.getElementClassList(cell); if (classList.indexOf('jp-CodeCell') !== -1) { @@ -918,10 +1188,13 @@ export class NotebookHelper { return false; } + await this.page.evaluate(cellIdx => { + window.galata.resetExecutionCount(cellIdx); + }, cellIndex); await this.page.keyboard.press( inplace === true ? 'Control+Enter' : 'Shift+Enter' ); - await this.waitForRun(); + await this.waitForRun(cellIndex); return true; } diff --git a/galata/src/helpers/sidebar.ts b/galata/src/helpers/sidebar.ts index f7922e3782d2..58600c3596c8 100644 --- a/galata/src/helpers/sidebar.ts +++ b/galata/src/helpers/sidebar.ts @@ -1,21 +1,21 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { ISettingRegistry } from '@jupyterlab/settingregistry'; +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; import { ElementHandle, Page } from '@playwright/test'; -import { - IPluginNameToInterfaceMap, - PLUGIN_ID_SETTINGS -} from '../inpage/tokens'; -import { MenuHelper } from './menu'; -import * as Utils from '../utils'; +import type { IPluginNameToInterfaceMap } from '../extension'; import { galata } from '../galata'; +import * as Utils from '../utils'; +import { MenuHelper } from './menu'; /** * Sidebar helpers */ export class SidebarHelper { - constructor(readonly page: Page, readonly menu: MenuHelper) {} + constructor( + readonly page: Page, + readonly menu: MenuHelper + ) {} /** * Whether a sidebar is opened or not @@ -137,21 +137,31 @@ export class SidebarHelper { async moveAllTabsToLeft(): Promise { await this.page.evaluate( async ({ pluginId }) => { - const settingRegistry = (await window.galataip.getPlugin( + const settingRegistry = (await window.galata.getPlugin( pluginId )) as ISettingRegistry; - const SIDEBAR_ID = '@jupyterlab/application-extension:sidebar'; - const overrides = ((await settingRegistry.get(SIDEBAR_ID, 'overrides')) - .composite as any) as { [index: string]: any }; - for (const widgetId of Object.keys(overrides)) { - overrides[widgetId] = 'left'; - } - // default location of the property inspector and debugger is right, move it to left during tests - overrides['jp-property-inspector'] = 'left'; - overrides['jp-debugger-sidebar'] = 'left'; - await settingRegistry.set(SIDEBAR_ID, 'overrides', overrides as any); + const SHELL_ID = '@jupyterlab/application-extension:shell'; + const sidebars = { + Debugger: 'left', + 'Property Inspector': 'left', + 'Extension Manager': 'left', + 'File Browser': 'left', + 'Sessions and Tabs': 'left', + 'Table of Contents': 'left' + }; + const currentLayout = (await settingRegistry.get( + SHELL_ID, + 'layout' + )) as any; + await settingRegistry.set(SHELL_ID, 'layout', { + single: { ...currentLayout.single, ...sidebars }, + multiple: { ...currentLayout.multiple, ...sidebars } + }); }, - { pluginId: PLUGIN_ID_SETTINGS as keyof IPluginNameToInterfaceMap } + { + pluginId: + '@jupyterlab/apputils-extension:settings' as keyof IPluginNameToInterfaceMap + } ); await this.page.waitForFunction(() => { @@ -201,10 +211,22 @@ export class SidebarHelper { side: galata.SidebarPosition = 'left' ): Promise | null> { return await this.page.$( - `#jp-${side}-stack .p-StackedPanel-child:not(.lm-mod-hidden)` + `#jp-${side}-stack .lm-StackedPanel-child:not(.lm-mod-hidden)` ); } + /** + * Get the tab bar of the sidebar + * + * @param side Position + * @returns Tab bar handle + */ + async getTabBar( + side: galata.SidebarPosition = 'left' + ): Promise | null> { + return await this.page.$(`.jp-SideBar.jp-mod-${side}`); + } + /** * Open a given sidebar * diff --git a/galata/src/helpers/statusbar.ts b/galata/src/helpers/statusbar.ts index f0d9b80a0582..560bf88b24b4 100644 --- a/galata/src/helpers/statusbar.ts +++ b/galata/src/helpers/statusbar.ts @@ -8,7 +8,10 @@ import { MenuHelper } from './menu'; * Status Bar helpers */ export class StatusBarHelper { - constructor(readonly page: Page, readonly menu: MenuHelper) {} + constructor( + readonly page: Page, + readonly menu: MenuHelper + ) {} /** * Whether the status bar is visible or not @@ -20,7 +23,7 @@ export class StatusBarHelper { const statusBar = document.querySelector( '#jp-main-statusbar' ) as HTMLElement; - return window.galataip.isElementVisible(statusBar); + return window.galata.isElementVisible(statusBar); }); } diff --git a/galata/src/helpers/style.ts b/galata/src/helpers/style.ts new file mode 100644 index 000000000000..b43a4f5dcfaf --- /dev/null +++ b/galata/src/helpers/style.ts @@ -0,0 +1,100 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { Page } from '@playwright/test'; + +interface IUnusedStyleCheckOptions { + /** + * List of rule fragments to match rules for runtime checks. + */ + fragments: string[]; + /** + * List of fragments to filter out rules which cannot (easily) be checked at runtime. + */ + exclude?: string[]; + /** + * Whether to check rules with pseudo-classes. + * + * Default: false. + */ + includePseudoClasses?: boolean; + /** + * Whether to include rules matching mod classes (`jp-mod-` and `.lm-mod-`). + * + * Default: false. + */ + includeModifiers?: boolean; +} + +/** + * CSS Style analysis helpers + */ +export class StyleHelper { + constructor(readonly page: Page) {} + + /** + * Collect all CSS selectors on page. + */ + async collectAllSelectors(): Promise { + return this.page.evaluate(() => + [...document.querySelectorAll('style')] + .filter(style => style.sheet !== null) + .map(style => [...style.sheet!.cssRules]) + .flat() + .filter((rule: CSSRule) => rule instanceof CSSStyleRule) + .map((rule: CSSStyleRule) => rule.selectorText) + ); + } + + /** + * Find unused CSS rules. + * + * @param options spcify which rules to include/exclude. + * @returns List of rules with no matching elements on the page. + */ + async findUnusedStyleRules( + options: IUnusedStyleCheckOptions + ): Promise { + let exclude = typeof options.exclude !== 'undefined' ? options.exclude : []; + if (!options.includeModifiers) { + exclude = [...exclude, ...['.jp-mod-', '.lm-mod-']]; + } + const relevantRules = (await this.collectAllSelectors()) + // detection of pseudo-elements with `document.querySelector` is impossible, + // so we just check their parents + .map(selector => + selector.replace( + /::?(after|before|backdrop|cue|cue-region|first-letter|first-line|file-selector-button|marker|placeholder|selection)/, + '' + ) + ) + .filter(selector => + options.includePseudoClasses ? true : !selector.match(/:\w+/) + ) + .filter(selector => + options.fragments.some(fragment => selector.includes(fragment)) + ) + .filter( + selector => !exclude.some(fragment => selector.includes(fragment)) + ); + const potentiallyUnusedRules = await this.page.evaluate( + relevantRules => + relevantRules.filter( + selector => document.querySelector(selector) == null + ), + relevantRules + ); + if (potentiallyUnusedRules.length !== 0) { + console.log( + potentiallyUnusedRules.length, + 'out of', + relevantRules.length, + 'CSS rules for', + options.fragments, + 'may be unused:', + potentiallyUnusedRules + ); + } + return potentiallyUnusedRules; + } +} diff --git a/galata/src/helpers/theme.ts b/galata/src/helpers/theme.ts index 3703cd0a2025..9d349b61e811 100644 --- a/galata/src/helpers/theme.ts +++ b/galata/src/helpers/theme.ts @@ -42,7 +42,7 @@ export class ThemeHelper { async setTheme(themeName: string): Promise { const page = this.page; await page.evaluate(async (themeName: string) => { - await window.galataip.setTheme(themeName); + await window.galata.setTheme(themeName); }, themeName); await page.waitForSelector('#jupyterlab-splash', { state: 'detached' }); diff --git a/galata/src/index.ts b/galata/src/index.ts index 2706959c46ca..07e8277cc80a 100644 --- a/galata/src/index.ts +++ b/galata/src/index.ts @@ -11,9 +11,9 @@ */ export { expect } from '@playwright/test'; +export * from './extension'; + export * from './benchmarkReporter'; export * from './galata'; -export * from './global'; -export * from './inpage/tokens'; export * from './fixtures'; export * from './jupyterlabpage'; diff --git a/galata/src/jupyterlabpage.ts b/galata/src/jupyterlabpage.ts index 41a9d9543cda..623abe64f535 100644 --- a/galata/src/jupyterlabpage.ts +++ b/galata/src/jupyterlabpage.ts @@ -1,11 +1,14 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import type { ElementHandle, Page, Response } from '@playwright/test'; -import * as path from 'path'; +import type { Notification } from '@jupyterlab/apputils'; +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; +import type { ElementHandle, Locator, Page, Response } from '@playwright/test'; import { ContentsHelper } from './contents'; +import type { IPluginNameToInterfaceMap } from './extension'; import { ActivityHelper, + DebuggerHelper, FileBrowserHelper, KernelHelper, LogConsoleHelper, @@ -14,6 +17,7 @@ import { PerformanceHelper, SidebarHelper, StatusBarHelper, + StyleHelper, ThemeHelper } from './helpers'; import * as Utils from './utils'; @@ -62,6 +66,11 @@ export interface IJupyterLabPage { */ readonly notebook: NotebookHelper; + /** + * JupyterLab notifications + */ + readonly notifications: Promise; + /** * Webbrowser performance helpers */ @@ -74,16 +83,32 @@ export interface IJupyterLabPage { * JupyterLab sidebar helpers */ readonly sidebar: SidebarHelper; + /** + * JupyterLab style helpers + */ + readonly style: StyleHelper; /** * JupyterLab theme helpers */ readonly theme: ThemeHelper; + /** + * JupyterLab launcher tab + */ + readonly launcher: Locator; + /** * Selector for launcher tab + * + * @deprecated You should use locator selector {@link launcher} */ readonly launcherSelector: string; + /** + * Debugger helper + */ + readonly debugger: DebuggerHelper; + /** * Getter for JupyterLab base URL */ @@ -162,8 +187,9 @@ export interface IJupyterLabPage { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle'; + waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit'; } ): Promise; @@ -186,7 +212,7 @@ export interface IJupyterLabPage { setSimpleMode(simple: boolean): Promise; /** - * Wait for a condition to be fulfilled + * Wait for a condition to be fulfilled * * @param condition Condition to fulfill * @param timeout Maximal time to wait for the condition to be true @@ -207,6 +233,8 @@ export interface IJupyterLabPage { * Factory for active activity tab xpath * * @returns The selector + * + * @deprecated You should use locator selector `getByRole('main').locator('.jp-mod-current[role="tab"]')` */ xpBuildActiveActivityTabSelector(): string; @@ -214,6 +242,9 @@ export interface IJupyterLabPage { * Factory for activity panel xpath by id * @param id Panel id * @returns The selector + * + * @deprecated You should use locator selector `getByRole('main').getByRole('tabpanel', { name })` + * where `name` is the name of the tab. */ xpBuildActivityPanelSelector(id: string): string; @@ -222,6 +253,8 @@ export interface IJupyterLabPage { * * @param name Activity name * @returns The selector + * + * @deprecated You should use locator selector `getByRole('main').getByRole('tab', { name })` */ xpBuildActivityTabSelector(name: string): string; @@ -230,6 +263,8 @@ export interface IJupyterLabPage { * * @param className Class name * @returns The selector + * + * @deprecated You should use locator CSS selector `locator('.className')` */ xpContainsClass(className: string): string; } @@ -254,7 +289,7 @@ export class JupyterLabPage implements IJupyterLabPage { ) { this.waitIsReady = waitForApplication; this.activity = new ActivityHelper(page); - this.contents = new ContentsHelper(baseURL, page, page.context().request); + this.contents = new ContentsHelper(page.context().request, page); this.filebrowser = new FileBrowserHelper(page, this.contents); this.kernel = new KernelHelper(page); this.logconsole = new LogConsoleHelper(page); @@ -269,7 +304,9 @@ export class JupyterLabPage implements IJupyterLabPage { this.performance = new PerformanceHelper(page); this.statusbar = new StatusBarHelper(page, this.menu); this.sidebar = new SidebarHelper(page, this.menu); + this.style = new StyleHelper(page); this.theme = new ThemeHelper(page); + this.debugger = new DebuggerHelper(page, this.sidebar, this.notebook); } /** @@ -307,6 +344,13 @@ export class JupyterLabPage implements IJupyterLabPage { */ readonly notebook: NotebookHelper; + /** + * JupyterLab notifications + */ + get notifications(): Promise { + return this.page.evaluate(async () => window.galata.getNotifications()); + } + /** * Webbrowser performance helpers */ @@ -321,13 +365,33 @@ export class JupyterLabPage implements IJupyterLabPage { * JupyterLab sidebar helpers */ readonly sidebar: SidebarHelper; + + /** + * JupyterLab style helpers + */ + readonly style: StyleHelper; + /** * JupyterLab theme helpers */ readonly theme: ThemeHelper; + /** + * JupyterLab debugger helper + */ + readonly debugger: DebuggerHelper; + + /** + * JupyterLab launcher tab + */ + get launcher(): Locator { + return this.activity.launcher; + } + /** * Selector for launcher tab + * + * @deprecated You should use locator selector {@link launcher} */ get launcherSelector(): string { return this.activity.launcherSelector; @@ -441,14 +505,9 @@ export class JupyterLabPage implements IJupyterLabPage { /** * Whether JupyterLab is in simple mode or not */ - isInSimpleMode = async (): Promise => { - const toggle = await this.page.$( - '#jp-single-document-mode button.jp-switch' - ); - const checked = (await toggle?.getAttribute('aria-checked')) === 'true'; - - return checked; - }; + isInSimpleMode(): Promise { + return Utils.isInSimpleMode(this.page); + } /** * Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the @@ -513,8 +572,20 @@ export class JupyterLabPage implements IJupyterLabPage { await this.kernel.shutdownAll(); // show status bar await this.statusbar.show(); - // make sure all sidebar tabs are on left - await this.sidebar.moveAllTabsToLeft(); + // Reset the layout + await this.page.evaluate( + async ({ pluginId }) => { + const settingRegistry = (await window.galata.getPlugin( + pluginId + )) as ISettingRegistry; + const SHELL_ID = '@jupyterlab/application-extension:shell'; + await settingRegistry.remove(SHELL_ID, 'layout'); + }, + { + pluginId: + '@jupyterlab/apputils-extension:settings' as keyof IPluginNameToInterfaceMap + } + ); // show Files tab on sidebar await this.sidebar.openTab('filebrowser'); // go to home folder @@ -576,6 +647,8 @@ export class JupyterLabPage implements IJupyterLabPage { /** * Factory for active activity tab xpath + * + * @deprecated You should use locator selector `getByRole('main').locator('.jp-mod-current[role="tab"]')` */ xpBuildActiveActivityTabSelector(): string { return Utils.xpBuildActiveActivityTabSelector(); @@ -584,6 +657,9 @@ export class JupyterLabPage implements IJupyterLabPage { /** * Factory for activity panel xpath by id * @param id Panel id + * + * @deprecated You should use locator selector `getByRole('main').getByRole('tabpanel', { name })` + * where `name` is the name of the tab. */ xpBuildActivityPanelSelector(id: string): string { return Utils.xpBuildActivityPanelSelector(id); @@ -592,6 +668,8 @@ export class JupyterLabPage implements IJupyterLabPage { /** * Factory for activity tab xpath by name * @param name Activity name + * + * @deprecated You should use locator selector `getByRole('main').getByRole('tab', { name })` */ xpBuildActivityTabSelector(name: string): string { return Utils.xpBuildActivityTabSelector(name); @@ -600,6 +678,8 @@ export class JupyterLabPage implements IJupyterLabPage { /** * Factory for element containing a given class xpath * @param className Class name + * + * @deprecated You should use locator CSS selector `locator('.className')` */ xpContainsClass(className: string): string { return Utils.xpContainsClass(className); @@ -609,21 +689,17 @@ export class JupyterLabPage implements IJupyterLabPage { * Inject the galata in-page helpers */ protected async hookHelpersUp(): Promise { - // Insert Galata in page helpers - await this.page.addScriptTag({ - path: path.resolve(__dirname, './lib-inpage/inpage.js') - }); - + // Check galata helpers are loaded const galataipDefined = await this.page.evaluate(() => { - return Promise.resolve(typeof window.galataip === 'object'); + return Promise.resolve(typeof window.galata === 'object'); }); if (!galataipDefined) { - throw new Error('Failed to inject galataip object into browser context'); + throw new Error('Failed to activate galata extension'); } const jlabAccessible = await this.page.evaluate(() => { - return Promise.resolve(typeof window.galataip.app === 'object'); + return Promise.resolve(typeof window.galata.app === 'object'); }); if (!jlabAccessible) { @@ -637,11 +713,7 @@ export class JupyterLabPage implements IJupyterLabPage { protected waitForAppStarted = async (): Promise => { return this.waitForCondition(() => this.page.evaluate(async () => { - if (typeof window.jupyterlab === 'object') { - // Wait for plugins to be loaded - await window.jupyterlab.started; - return true; - } else if (typeof window.jupyterapp === 'object') { + if (typeof window.jupyterapp === 'object') { // Wait for plugins to be loaded await window.jupyterapp.started; return true; diff --git a/galata/src/playwright-config.ts b/galata/src/playwright-config.ts index 13bfda52772f..a872bc7b889d 100644 --- a/galata/src/playwright-config.ts +++ b/galata/src/playwright-config.ts @@ -5,7 +5,10 @@ import { PlaywrightTestConfig } from '@playwright/test'; // Default Playwright configuration for JupyterLab module.exports = { - reporter: [[process.env.CI ? 'dot' : 'list'], ['html']], + reporter: [ + [process.env.CI ? 'github' : 'list'], + ['html', { open: process.env.CI ? 'never' : 'on-failure' }] + ], reportSlowTests: null, timeout: 60000, use: { @@ -17,6 +20,7 @@ module.exports = { viewport: { width: 1024, height: 768 }, // Artifacts + trace: 'on-first-retry', video: 'retain-on-failure' } } as PlaywrightTestConfig; diff --git a/galata/src/utils.ts b/galata/src/utils.ts index 0a4ce313644a..db163f81c25d 100644 --- a/galata/src/utils.ts +++ b/galata/src/utils.ts @@ -221,6 +221,8 @@ export async function waitForTransition( * * @param className Class name * @returns Selector + * + * @deprecated You should use locator CSS selector `locator('.className')` */ export function xpContainsClass(className: string): string { return `contains(concat(" ", normalize-space(@class), " "), " ${className} ")`; @@ -231,9 +233,11 @@ export function xpContainsClass(className: string): string { * * @param name Activity name * @returns Selector + * + * @deprecated You should use locator selector `getByRole('main').getByRole('tab', { name })` */ export function xpBuildActivityTabSelector(name: string): string { - return `//div[${xpContainsClass('jp-Activity')}]/ul/li[${xpContainsClass( + return `//div[contains(@role, "main")]//ul/li[${xpContainsClass( 'lm-TabBar-tab' )} and ./div[text()="${name}" and ${xpContainsClass('lm-TabBar-tabLabel')}]]`; } @@ -243,6 +247,9 @@ export function xpBuildActivityTabSelector(name: string): string { * * @param id Activity id * @returns Selector + * + * @deprecated You should use locator selector `getByRole('main').getByRole('tabpanel', { name })` + * where `name` is the name of the tab. */ export function xpBuildActivityPanelSelector(id: string): string { return `//div[@id='${id}' and ${xpContainsClass( @@ -254,11 +261,21 @@ export function xpBuildActivityPanelSelector(id: string): string { * Get the selector to look for the currently active activity tab * * @returns Selector + * + * @deprecated You should use locator selector `getByRole('main').locator('.jp-mod-current[role="tab"]')` */ export function xpBuildActiveActivityTabSelector(): string { - return `//div[${xpContainsClass('jp-Activity')}]/ul/li[${xpContainsClass( + return `//div[contains(@role, "main")]//ul/li[${xpContainsClass( 'lm-TabBar-tab' - )} and ${xpContainsClass('lm-mod-current')} and ./div[${xpContainsClass( + )} and ${xpContainsClass('jp-mod-current')} and ./div[${xpContainsClass( 'lm-TabBar-tabLabel' )}]]`; } + +/** + * Whether JupyterLab is in simple mode or not + */ +export function isInSimpleMode(page: Page): Promise { + const toggle = page.getByRole('switch', { name: 'Simple' }); + return toggle.isChecked(); +} diff --git a/galata/src/vega-statistics.d.ts b/galata/src/vega-statistics.d.ts index b335f5edb305..dd70ea000eb5 100644 --- a/galata/src/vega-statistics.d.ts +++ b/galata/src/vega-statistics.d.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + // Type definitions for vega-statistics // Project: vega-statistics // Definitions by: Jupyter Development Team diff --git a/galata/test/benchmark/notebook.spec.ts b/galata/test/benchmark/notebook.spec.ts index ebda73ff1b5b..c5c3a939ea53 100644 --- a/galata/test/benchmark/notebook.spec.ts +++ b/galata/test/benchmark/notebook.spec.ts @@ -21,8 +21,8 @@ const parameters = [].concat( test.describe('Benchmark', () => { // Generate the files for the benchmark - test.beforeAll(async ({ baseURL, request }) => { - const content = galata.newContentsHelper(baseURL, undefined, request); + test.beforeAll(async ({ request }) => { + const content = galata.newContentsHelper(request); const codeContent = galata.Notebook.generateNotebook(300, 'code', [ 'for x in range(OUTPUT_LENGTH):\n', ' print(f"{PREFIX} {x}")' @@ -79,8 +79,8 @@ test.describe('Benchmark', () => { }); // Remove benchmark files - test.afterAll(async ({ baseURL, request }) => { - const content = galata.newContentsHelper(baseURL, undefined, request); + test.afterAll(async ({ request }) => { + const content = galata.newContentsHelper(request); await content.deleteDirectory(tmpPath); }); @@ -140,8 +140,10 @@ test.describe('Benchmark', () => { // Shutdown the kernel to be sure it does not get in our way (especially for the close action) await page.click('li[role="menuitem"]:has-text("Kernel")'); - await page.click('ul[role="menu"] >> text=Shut Down All Kernelsâ€Ļ'); - await page.click(':nth-match(button:has-text("Shut Down All"), 3)'); + await page.click( + '.lm-Menu ul[role="menu"] >> text=Shut Down All Kernelsâ€Ļ' + ); + await page.click('button:has-text("Shut Down All") >> nth=-1'); // Click on the last matched button. // Open text file const fromTime = await perf.measure(async () => { @@ -192,7 +194,7 @@ test.describe('Benchmark', () => { // Close notebook await page.click('li[role="menuitem"]:has-text("File")'); const closeTime = await perf.measure(async () => { - await page.click('ul[role="menu"] >> text=Close Tab'); + await page.click('.lm-Menu ul[role="menu"] >> text=Close Tab'); // Revert changes so we don't measure saving const dimissButton = page.locator('button:has-text("Discard")'); if (await dimissButton.isVisible({ timeout: 50 })) { diff --git a/galata/test/benchmark/notebook.spec.ts-snapshots/large-code-notebook-ipynb-benchmark-linux.png b/galata/test/benchmark/notebook.spec.ts-snapshots/large-code-notebook-ipynb-benchmark-linux.png index 378971d58db7..989668a8512d 100644 Binary files a/galata/test/benchmark/notebook.spec.ts-snapshots/large-code-notebook-ipynb-benchmark-linux.png and b/galata/test/benchmark/notebook.spec.ts-snapshots/large-code-notebook-ipynb-benchmark-linux.png differ diff --git a/galata/test/benchmark/notebook.spec.ts-snapshots/large-md-notebook-ipynb-benchmark-linux.png b/galata/test/benchmark/notebook.spec.ts-snapshots/large-md-notebook-ipynb-benchmark-linux.png index cd0a944b83a0..9431242025e8 100644 Binary files a/galata/test/benchmark/notebook.spec.ts-snapshots/large-md-notebook-ipynb-benchmark-linux.png and b/galata/test/benchmark/notebook.spec.ts-snapshots/large-md-notebook-ipynb-benchmark-linux.png differ diff --git a/galata/test/documentation/commands.test.ts b/galata/test/documentation/commands.test.ts new file mode 100644 index 000000000000..327999b5fc17 --- /dev/null +++ b/galata/test/documentation/commands.test.ts @@ -0,0 +1,63 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { test } from '@jupyterlab/galata'; +import { expect } from '@playwright/test'; +import * as fs from 'fs-extra'; + +test('All commands must have a default label', async ({ page }, testInfo) => { + const commands = await page.evaluate(async () => { + const registry = window.jupyterapp.commands; + const shortcuts = registry.keyBindings; + const commandIds = registry.listCommands(); + + // Get more information about the commands + const commands: { + id: string; + label: string; + caption: string; + shortcuts?: string[]; + }[] = commandIds + .filter(id => !id.startsWith('_') && !id.startsWith('@jupyter-widgets')) + .sort() + .map(id => { + try { + return { + id, + label: registry.label(id), + caption: registry.caption(id), + shortcuts: [ + ...(shortcuts.find(shortcut => shortcut.command === id)?.keys ?? + []) + ] + }; + } catch (reason) { + console.error(reason); + return { + id, + label: '', + caption: '', + shortcuts: [ + ...(shortcuts.find(shortcut => shortcut.command === id)?.keys ?? + []) + ] + }; + } + }); + + return Promise.resolve(commands); + }); + + if (!(await fs.pathExists(testInfo.snapshotDir))) { + await fs.mkdir(testInfo.snapshotDir); + } + await fs.writeJSON(testInfo.snapshotPath('commandsList.json'), commands, { + encoding: 'utf-8', + spaces: 2 + }); + + // All commands must at least define a label + const missingLabel = commands.filter(command => !command.label); + + expect(missingLabel).toEqual([]); +}); diff --git a/galata/test/documentation/commands.test.ts-snapshots/commandsList-documentation-linux.json b/galata/test/documentation/commands.test.ts-snapshots/commandsList-documentation-linux.json new file mode 100644 index 000000000000..d1dfea719fa0 --- /dev/null +++ b/galata/test/documentation/commands.test.ts-snapshots/commandsList-documentation-linux.json @@ -0,0 +1,2268 @@ +[ + { + "id": "application:activate-next-tab", + "label": "Activate Next Tab", + "caption": "", + "shortcuts": [ + "Ctrl Shift ]" + ] + }, + { + "id": "application:activate-next-tab-bar", + "label": "Activate Next Tab Bar", + "caption": "", + "shortcuts": [ + "Ctrl Shift ." + ] + }, + { + "id": "application:activate-previous-tab", + "label": "Activate Previous Tab", + "caption": "", + "shortcuts": [ + "Ctrl Shift [" + ] + }, + { + "id": "application:activate-previous-tab-bar", + "label": "Activate Previous Tab Bar", + "caption": "", + "shortcuts": [ + "Ctrl Shift ," + ] + }, + { + "id": "application:close", + "label": "Close Tab", + "caption": "", + "shortcuts": [ + "Alt W" + ] + }, + { + "id": "application:close-all", + "label": "Close All Tabs", + "caption": "", + "shortcuts": [] + }, + { + "id": "application:close-other-tabs", + "label": "Close All Other Tabs", + "caption": "", + "shortcuts": [] + }, + { + "id": "application:close-right-tabs", + "label": "Close Tabs to Right", + "caption": "", + "shortcuts": [] + }, + { + "id": "application:reset-layout", + "label": "Reset Default Layout", + "caption": "", + "shortcuts": [] + }, + { + "id": "application:set-mode", + "label": "Set the layout `mode`.", + "caption": "The layout `mode` can be \"single-document\" or \"multiple-document\".", + "shortcuts": [] + }, + { + "id": "application:toggle-header", + "label": "Show Header", + "caption": "", + "shortcuts": [] + }, + { + "id": "application:toggle-left-area", + "label": "Show Left Sidebar", + "caption": "", + "shortcuts": [ + "Ctrl B" + ] + }, + { + "id": "application:toggle-mode", + "label": "Simple Interface", + "caption": "", + "shortcuts": [ + "Ctrl Shift D" + ] + }, + { + "id": "application:toggle-presentation-mode", + "label": "Presentation Mode", + "caption": "", + "shortcuts": [] + }, + { + "id": "application:toggle-right-area", + "label": "Show Right Sidebar", + "caption": "", + "shortcuts": [] + }, + { + "id": "application:toggle-side-tabbar", + "label": "Show Left Activity Bar", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:activate-command-palette", + "label": "Activate Command Palette", + "caption": "", + "shortcuts": [ + "Ctrl Shift C" + ] + }, + { + "id": "apputils:change-font", + "label": "waiting for fonts", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:change-theme", + "label": "Switch to the provided `theme`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:decr-font-size", + "label": "Decrease Font Size", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:dismiss-notification", + "label": "Dismiss a notification", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:display-notifications", + "label": "Show Notifications", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:display-shortcuts", + "label": "Show Keyboard Shortcuts", + "caption": "Show relevant keyboard shortcuts for the current active widget", + "shortcuts": [ + "Ctrl Shift H" + ] + }, + { + "id": "apputils:incr-font-size", + "label": "Increase Font Size", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:load-statedb", + "label": "Load state for the current workspace.", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:notify", + "label": "Emit a notification", + "caption": "Notification is described by {message: string, type?: string, options?: {autoClose?: number | false, actions: {label: string, commandId: string, args?: ReadOnlyJSONObject, caption?: string, className?: string}[], data?: ReadOnlyJSONValue}}.", + "shortcuts": [] + }, + { + "id": "apputils:print", + "label": "Printâ€Ļ", + "caption": "", + "shortcuts": [ + "Ctrl P" + ] + }, + { + "id": "apputils:reset", + "label": "Reset Application State", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:reset-on-load", + "label": "Reset state when loading for the workspace.", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:run-all-enabled", + "label": "Run All Enabled Commands Passed as Args", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:run-first-enabled", + "label": "Run First Enabled Command", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:theme-scrollbars", + "label": "Theme Scrollbars", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:toggle-header", + "label": "Show Header Above Content", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:update-notification", + "label": "Update a notification", + "caption": "Notification is described by {id: string, message: string, type?: string, options?: {autoClose?: number | false, actions: {label: string, commandId: string, args?: ReadOnlyJSONObject, caption?: string, className?: string}[], data?: ReadOnlyJSONValue}}.", + "shortcuts": [] + }, + { + "id": "code-viewer:open", + "label": "Open Code Viewer", + "caption": "", + "shortcuts": [] + }, + { + "id": "completer:invoke-console", + "label": "Display the completion helper.", + "caption": "", + "shortcuts": [ + "Tab" + ] + }, + { + "id": "completer:invoke-file", + "label": "Display the completion helper.", + "caption": "", + "shortcuts": [ + "Tab" + ] + }, + { + "id": "completer:invoke-notebook", + "label": "Display the completion helper.", + "caption": "", + "shortcuts": [ + "Tab" + ] + }, + { + "id": "completer:select-console", + "label": "Select the completion suggestion.", + "caption": "", + "shortcuts": [ + "Enter" + ] + }, + { + "id": "completer:select-file", + "label": "Select the completion suggestion.", + "caption": "", + "shortcuts": [ + "Enter" + ] + }, + { + "id": "completer:select-notebook", + "label": "Select the completion suggestion.", + "caption": "", + "shortcuts": [ + "Enter" + ] + }, + { + "id": "console:change-kernel", + "label": "Change Kernelâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:clear", + "label": "Clear Console Cells", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:close-and-shutdown", + "label": "Close and Shut Downâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:create", + "label": "Console", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:get-kernel", + "label": "Get Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:inject", + "label": "Inject some code in a console.", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:interaction-mode", + "label": "Set the console interaction mode.", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:interrupt-kernel", + "label": "Interrupt Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:linebreak", + "label": "Insert Line Break", + "caption": "", + "shortcuts": [ + "Enter" + ] + }, + { + "id": "console:open", + "label": "Open a console for the provided `path`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:replace-selection", + "label": "Replace Selection in Console", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:restart-kernel", + "label": "Restart Kernelâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:run-forced", + "label": "Run Cell (forced)", + "caption": "", + "shortcuts": [ + "Shift Enter" + ] + }, + { + "id": "console:run-unforced", + "label": "Run Cell (unforced)", + "caption": "", + "shortcuts": [ + "Enter" + ] + }, + { + "id": "console:shutdown", + "label": "Shut Down", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:toggle-autoclosing-brackets", + "label": "Auto Close Brackets for Code Console Prompt", + "caption": "", + "shortcuts": [] + }, + { + "id": "console:toggle-show-all-kernel-activity", + "label": "Show All Kernel Activity", + "caption": "", + "shortcuts": [] + }, + { + "id": "csv:go-to-line", + "label": "Go to Line", + "caption": "", + "shortcuts": [] + }, + { + "id": "debugger:continue", + "label": "Pause", + "caption": "Pause", + "shortcuts": [ + "F9" + ] + }, + { + "id": "debugger:copy-to-clipboard", + "label": "Copy to Clipboard", + "caption": "Copy text representation of the value to clipboard", + "shortcuts": [] + }, + { + "id": "debugger:copy-to-globals", + "label": "Copy Variable to Globals", + "caption": "Copy variable to globals scope", + "shortcuts": [] + }, + { + "id": "debugger:evaluate", + "label": "Evaluate Code", + "caption": "Evaluate Code", + "shortcuts": [] + }, + { + "id": "debugger:inspect-variable", + "label": "Inspect Variable", + "caption": "Inspect Variable", + "shortcuts": [] + }, + { + "id": "debugger:next", + "label": "Next", + "caption": "Next", + "shortcuts": [ + "F10" + ] + }, + { + "id": "debugger:pause-on-exceptions", + "label": "Breakpoints on exception", + "shortcuts": [] + }, + { + "id": "debugger:render-mime-variable", + "label": "Render Variable", + "caption": "Render variable according to its mime type", + "shortcuts": [] + }, + { + "id": "debugger:restart-debug", + "label": "Restart Kernel and Debugâ€Ļ", + "caption": "Restart Kernel and Debugâ€Ļ", + "shortcuts": [] + }, + { + "id": "debugger:show-panel", + "label": "Debugger Panel", + "caption": "", + "shortcuts": [ + "Ctrl Shift E" + ] + }, + { + "id": "debugger:stepIn", + "label": "Step In", + "caption": "Step In", + "shortcuts": [ + "F11" + ] + }, + { + "id": "debugger:stepOut", + "label": "Step Out", + "caption": "Step Out", + "shortcuts": [ + "Shift F11" + ] + }, + { + "id": "debugger:terminate", + "label": "Terminate", + "caption": "Terminate", + "shortcuts": [ + "Shift F9" + ] + }, + { + "id": "docmanager:clone", + "label": "New View for ", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:delete", + "label": "Delete ", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:delete-file", + "label": "Delete ", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:download", + "label": "Download", + "caption": "Download the file to your computer", + "shortcuts": [] + }, + { + "id": "docmanager:duplicate", + "label": "Duplicate ", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:new-untitled", + "label": "New undefined", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:open", + "label": "Open the provided `path`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:open-browser-tab", + "label": "Open in New Browser Tab", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:reload", + "label": "Reload from Disk", + "caption": "Reload contents from disk", + "shortcuts": [] + }, + { + "id": "docmanager:rename", + "label": "Renameâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:restore-checkpoint", + "label": "Revert to Checkpointâ€Ļ", + "caption": "Revert contents to previous checkpoint", + "shortcuts": [] + }, + { + "id": "docmanager:save", + "label": "Save ", + "caption": "Save and create checkpoint", + "shortcuts": [ + "Ctrl S" + ] + }, + { + "id": "docmanager:save-all", + "label": "Save All", + "caption": "Save all open documents", + "shortcuts": [] + }, + { + "id": "docmanager:save-as", + "label": "Save Asâ€Ļ", + "caption": "Save with new path", + "shortcuts": [ + "Ctrl Shift S" + ] + }, + { + "id": "docmanager:show-in-file-browser", + "label": "Show in File Browser", + "caption": "", + "shortcuts": [] + }, + { + "id": "docmanager:toggle-autosave", + "label": "Autosave Documents", + "caption": "", + "shortcuts": [] + }, + { + "id": "documentsearch:end", + "label": "End Search", + "caption": "", + "shortcuts": [ + "Escape" + ] + }, + { + "id": "documentsearch:highlightNext", + "label": "Find Next", + "caption": "", + "shortcuts": [ + "Ctrl G" + ] + }, + { + "id": "documentsearch:highlightPrevious", + "label": "Find Previous", + "caption": "", + "shortcuts": [ + "Ctrl Shift G" + ] + }, + { + "id": "documentsearch:start", + "label": "Findâ€Ļ", + "caption": "", + "shortcuts": [ + "Ctrl F" + ] + }, + { + "id": "documentsearch:startWithReplace", + "label": "Find and Replaceâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "documentsearch:toggleSearchInSelection", + "label": "Search in Selection", + "caption": "", + "shortcuts": [ + "Alt L" + ] + }, + { + "id": "editmenu:clear-all", + "label": "Clear All", + "caption": "", + "shortcuts": [] + }, + { + "id": "editmenu:clear-current", + "label": "Clear", + "caption": "", + "shortcuts": [] + }, + { + "id": "editmenu:go-to-line", + "label": "Go to Lineâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "editmenu:open", + "label": "Open Edit Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "editmenu:redo", + "label": "Redo", + "caption": "", + "shortcuts": [ + "Ctrl Shift Z" + ] + }, + { + "id": "editmenu:undo", + "label": "Undo", + "caption": "", + "shortcuts": [ + "Ctrl Z" + ] + }, + { + "id": "extensionmanager:show-panel", + "label": "Extension Manager", + "caption": "", + "shortcuts": [ + "Ctrl Shift X" + ] + }, + { + "id": "extensionmanager:toggle", + "label": "Enable Extension Manager", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:activate", + "label": "Open the file browser for the provided `path`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:copy", + "label": "Copy", + "caption": "", + "shortcuts": [ + "Ctrl C" + ] + }, + { + "id": "filebrowser:copy-download-link", + "label": "Copy Download Link", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:copy-path", + "label": "Copy Path", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:create-new-directory", + "label": "New Folder", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:create-new-file", + "label": "New File", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:create-new-markdown-file", + "label": "New Markdown File", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:cut", + "label": "Cut", + "caption": "", + "shortcuts": [ + "Ctrl X" + ] + }, + { + "id": "filebrowser:delete", + "label": "Delete", + "caption": "", + "shortcuts": [ + "Delete" + ] + }, + { + "id": "filebrowser:download", + "label": "Download", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:duplicate", + "label": "Duplicate", + "caption": "", + "shortcuts": [ + "Ctrl D" + ] + }, + { + "id": "filebrowser:go-to-path", + "label": "Update the file browser to display the provided `path`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:go-up", + "label": "go up", + "caption": "", + "shortcuts": [ + "Backspace" + ] + }, + { + "id": "filebrowser:hide-main", + "label": "Hide the file browser.", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:open", + "label": "Open", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:open-browser-tab", + "label": "Open in New Browser Tab", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:open-path", + "label": "Open from Pathâ€Ļ", + "caption": "Open from path", + "shortcuts": [] + }, + { + "id": "filebrowser:open-url", + "label": "Open from URLâ€Ļ", + "caption": "Open from URL", + "shortcuts": [] + }, + { + "id": "filebrowser:paste", + "label": "Paste", + "caption": "", + "shortcuts": [ + "Ctrl V" + ] + }, + { + "id": "filebrowser:refresh", + "label": "Refresh File List", + "caption": "Refresh the file browser.", + "shortcuts": [] + }, + { + "id": "filebrowser:rename", + "label": "Rename", + "caption": "", + "shortcuts": [ + "F2" + ] + }, + { + "id": "filebrowser:search", + "label": "Search on File Names", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:share-main", + "label": "Copy Shareable Link", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:shutdown", + "label": "Shut Down Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:toggle-file-checkboxes", + "label": "Show File Checkboxes", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:toggle-file-size", + "label": "Show File Size Column", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:toggle-hidden-files", + "label": "Show Hidden Files", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:toggle-last-modified", + "label": "Show Last Modified Column", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:toggle-main", + "label": "File Browser", + "caption": "", + "shortcuts": [ + "Ctrl Shift F" + ] + }, + { + "id": "filebrowser:toggle-navigate-to-current-directory", + "label": "Show Active File in File Browser", + "caption": "", + "shortcuts": [] + }, + { + "id": "filebrowser:toggle-sort-notebooks-first", + "label": "Sort Notebooks Above Files", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:change-font-size", + "label": "Decrease Font Size", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:change-language", + "label": "Change editor language.", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:change-tabs", + "label": "Indent with Tab", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:change-theme", + "label": "jupyter", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:copy", + "label": "Copy", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:create-console", + "label": "Create Console for Editor", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:create-new", + "label": "Text File", + "caption": "Create a new text file", + "shortcuts": [] + }, + { + "id": "fileeditor:create-new-markdown-file", + "label": "Markdown File", + "caption": "Create a new markdown file", + "shortcuts": [] + }, + { + "id": "fileeditor:cut", + "label": "Cut", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:find", + "label": "Findâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:go-to-line", + "label": "Go to Lineâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:markdown-preview", + "label": "Show Markdown Preview", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:paste", + "label": "Paste", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:redo", + "label": "Redo", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:replace-selection", + "label": "Replace Selection in Editor", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:restart-console", + "label": "Restart Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:run-all", + "label": "Run All Code", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:run-code", + "label": "Run Selected Code", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:select-all", + "label": "Select All", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-autoclosing-brackets", + "label": "Auto Close Brackets in Text Editor", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-autoclosing-brackets-universal", + "label": "Auto Close Brackets", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-current-line-numbers", + "label": "Show Line Numbers", + "caption": "Show the line numbers for the current file.", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-current-line-wrap", + "label": "Wrap Words", + "caption": "Wrap words for the current file.", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-current-match-brackets", + "label": "Match Brackets", + "caption": "Change match brackets for the current file.", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-line-numbers", + "label": "Show Line Numbers", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-line-wrap", + "label": "Word Wrap", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-match-brackets", + "label": "Match Brackets", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:undo", + "label": "Undo", + "caption": "", + "shortcuts": [] + }, + { + "id": "filemenu:close-and-cleanup", + "label": "Close and Shut Down", + "caption": "", + "shortcuts": [ + "Ctrl Shift Q" + ] + }, + { + "id": "filemenu:create-console", + "label": "New Console for Activity", + "caption": "", + "shortcuts": [] + }, + { + "id": "filemenu:logout", + "label": "Log Out", + "caption": "Log out of JupyterLab", + "shortcuts": [] + }, + { + "id": "filemenu:open", + "label": "Open File Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "filemenu:shutdown", + "label": "Shut Down", + "caption": "Shut down JupyterLab", + "shortcuts": [] + }, + { + "id": "help:about", + "label": "About JupyterLab", + "caption": "", + "shortcuts": [] + }, + { + "id": "help:jupyter-forum", + "label": "Jupyter Forum", + "caption": "", + "shortcuts": [] + }, + { + "id": "help:license-report", + "label": "Download All Licenses as Markdown", + "caption": "Download All Licenses as Markdown", + "shortcuts": [] + }, + { + "id": "help:licenses", + "label": "Licenses", + "caption": "", + "shortcuts": [] + }, + { + "id": "help:licenses-refresh", + "label": "Refresh Licenses", + "caption": "Refresh Licenses", + "shortcuts": [] + }, + { + "id": "help:open", + "label": "Open the provided `url` in a tab.", + "caption": "", + "shortcuts": [] + }, + { + "id": "helpmenu:get-kernel", + "label": "Get Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "helpmenu:open", + "label": "Open Help Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "htmlviewer:trust-html", + "label": "Trust HTML File", + "caption": "Whether the HTML file is trusted.\n Trusting the file allows scripts to run in it,\n which may result in security risks.\n Only enable for files you trust.", + "shortcuts": [] + }, + { + "id": "imageviewer:flip-horizontal", + "label": "Flip image horizontally", + "caption": "", + "shortcuts": [ + "H" + ] + }, + { + "id": "imageviewer:flip-vertical", + "label": "Flip image vertically", + "caption": "", + "shortcuts": [ + "V" + ] + }, + { + "id": "imageviewer:invert-colors", + "label": "Invert Colors", + "caption": "", + "shortcuts": [ + "I" + ] + }, + { + "id": "imageviewer:reset-image", + "label": "Reset Image", + "caption": "", + "shortcuts": [ + "0" + ] + }, + { + "id": "imageviewer:rotate-clockwise", + "label": "Rotate Clockwise", + "caption": "", + "shortcuts": [ + "]" + ] + }, + { + "id": "imageviewer:rotate-counterclockwise", + "label": "Rotate Counterclockwise", + "caption": "", + "shortcuts": [ + "[" + ] + }, + { + "id": "imageviewer:zoom-in", + "label": "Zoom In", + "caption": "", + "shortcuts": [ + "=" + ] + }, + { + "id": "imageviewer:zoom-out", + "label": "Zoom Out", + "caption": "", + "shortcuts": [ + "-" + ] + }, + { + "id": "inspector:close", + "label": "Hide Contextual Help", + "caption": "Live updating code documentation from the active kernel", + "shortcuts": [ + "Ctrl I" + ] + }, + { + "id": "inspector:open", + "label": "Show Contextual Help", + "caption": "Live updating code documentation from the active kernel", + "shortcuts": [ + "Ctrl I" + ] + }, + { + "id": "inspector:toggle", + "label": "Show Contextual Help", + "caption": "Live updating code documentation from the active kernel", + "shortcuts": [] + }, + { + "id": "jupyterlab-translation:en", + "label": "English", + "caption": "English", + "shortcuts": [] + }, + { + "id": "jupyterlab-translation:zh_CN", + "label": "Chinese (Simplified, China) - 中文 (įŽ€äŊ“, 中å›Ŋ)", + "caption": "Chinese (Simplified, China) - 中文 (įŽ€äŊ“, 中å›Ŋ)", + "shortcuts": [] + }, + { + "id": "kernelmenu:change", + "label": "Change Kernelâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "kernelmenu:interrupt", + "label": "Interrupt Kernel", + "caption": "Interrupt the kernel", + "shortcuts": [ + "I", + "I" + ] + }, + { + "id": "kernelmenu:open", + "label": "Open Kernel Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "kernelmenu:reconnect-to-kernel", + "label": "Reconnect to Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "kernelmenu:restart", + "label": "Restart Kernelâ€Ļ", + "caption": "Restart the kernel", + "shortcuts": [ + "0", + "0" + ] + }, + { + "id": "kernelmenu:restart-and-clear", + "label": "Restart Kernel and Clearâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "kernelmenu:shutdown", + "label": "Shut Down Kernel", + "caption": "Shut down kernel", + "shortcuts": [] + }, + { + "id": "kernelmenu:shutdownAll", + "label": "Shut Down All Kernelsâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "launcher:create", + "label": "New Launcher", + "caption": "", + "shortcuts": [ + "Ctrl Shift L" + ] + }, + { + "id": "logconsole:add-checkpoint", + "label": "Add Checkpoint", + "caption": "", + "shortcuts": [] + }, + { + "id": "logconsole:clear", + "label": "Clear Log", + "caption": "", + "shortcuts": [] + }, + { + "id": "logconsole:open", + "label": "Show Log Console", + "caption": "", + "shortcuts": [] + }, + { + "id": "logconsole:set-level", + "label": "Set log level to `level`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "mainmenu:open-first", + "label": "Open First Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "markdownviewer:edit", + "label": "Show Markdown Editor", + "caption": "", + "shortcuts": [] + }, + { + "id": "markdownviewer:open", + "label": "Markdown Preview", + "caption": "", + "shortcuts": [] + }, + { + "id": "mathjax:clipboard", + "label": "MathJax Copy Latex", + "caption": "", + "shortcuts": [] + }, + { + "id": "mathjax:scale", + "label": "Mathjax Scale Reset", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:change-cell-to-code", + "label": "Change to Code Cell Type", + "caption": "", + "shortcuts": [ + "Y" + ] + }, + { + "id": "notebook:change-cell-to-heading-1", + "label": "Change to Heading 1", + "caption": "", + "shortcuts": [ + "1" + ] + }, + { + "id": "notebook:change-cell-to-heading-2", + "label": "Change to Heading 2", + "caption": "", + "shortcuts": [ + "2" + ] + }, + { + "id": "notebook:change-cell-to-heading-3", + "label": "Change to Heading 3", + "caption": "", + "shortcuts": [ + "3" + ] + }, + { + "id": "notebook:change-cell-to-heading-4", + "label": "Change to Heading 4", + "caption": "", + "shortcuts": [ + "4" + ] + }, + { + "id": "notebook:change-cell-to-heading-5", + "label": "Change to Heading 5", + "caption": "", + "shortcuts": [ + "5" + ] + }, + { + "id": "notebook:change-cell-to-heading-6", + "label": "Change to Heading 6", + "caption": "", + "shortcuts": [ + "6" + ] + }, + { + "id": "notebook:change-cell-to-markdown", + "label": "Change to Markdown Cell Type", + "caption": "", + "shortcuts": [ + "M" + ] + }, + { + "id": "notebook:change-cell-to-raw", + "label": "Change to Raw Cell Type", + "caption": "", + "shortcuts": [ + "R" + ] + }, + { + "id": "notebook:change-kernel", + "label": "Change Kernelâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:clear-all-cell-outputs", + "label": "Clear Outputs of All Cells", + "caption": "Clear all outputs of all cells", + "shortcuts": [] + }, + { + "id": "notebook:clear-cell-output", + "label": "Clear Cell Output", + "caption": "Clear outputs for the selected cells", + "shortcuts": [] + }, + { + "id": "notebook:close-and-shutdown", + "label": "Close and Shut Down Notebook", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:collapse-all-headings", + "label": "Collapse All Headings", + "caption": "", + "shortcuts": [ + "Ctrl Shift ArrowLeft" + ] + }, + { + "id": "notebook:copy-cell", + "label": "Copy Cell", + "caption": "Copy this cell", + "shortcuts": [ + "C" + ] + }, + { + "id": "notebook:copy-to-clipboard", + "label": "Copy Output to Clipboard", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:create-console", + "label": "New Console for Notebook", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:create-new", + "label": "Notebook", + "caption": "Create a new notebook", + "shortcuts": [] + }, + { + "id": "notebook:create-output-view", + "label": "Create New View for Cell Output", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:cut-cell", + "label": "Cut Cell", + "caption": "Cut this cell", + "shortcuts": [ + "X" + ] + }, + { + "id": "notebook:delete-cell", + "label": "Delete Cell", + "caption": "Delete this cell", + "shortcuts": [ + "D", + "D" + ] + }, + { + "id": "notebook:deselect-all", + "label": "Deselect All Cells", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:disable-output-scrolling", + "label": "Disable Scrolling for Outputs", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:duplicate-below", + "label": "Duplicate Cell Below", + "caption": "Create a duplicate of this cell below", + "shortcuts": [] + }, + { + "id": "notebook:enable-output-scrolling", + "label": "Enable Scrolling for Outputs", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:enter-command-mode", + "label": "Enter Command Mode", + "caption": "", + "shortcuts": [ + "Escape" + ] + }, + { + "id": "notebook:enter-edit-mode", + "label": "Enter Edit Mode", + "caption": "", + "shortcuts": [ + "Enter" + ] + }, + { + "id": "notebook:expand-all-headings", + "label": "Expand All Headings", + "caption": "", + "shortcuts": [ + "Ctrl Shift ArrowRight" + ] + }, + { + "id": "notebook:export-to-format", + "label": "Save and Export Notebook to the given `format`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:extend-marked-cells-above", + "label": "Extend Selection Above", + "caption": "", + "shortcuts": [ + "Shift ArrowUp" + ] + }, + { + "id": "notebook:extend-marked-cells-below", + "label": "Extend Selection Below", + "caption": "", + "shortcuts": [ + "Shift ArrowDown" + ] + }, + { + "id": "notebook:extend-marked-cells-bottom", + "label": "Extend Selection to Bottom", + "caption": "", + "shortcuts": [ + "Shift End" + ] + }, + { + "id": "notebook:extend-marked-cells-top", + "label": "Extend Selection to Top", + "caption": "", + "shortcuts": [ + "Shift Home" + ] + }, + { + "id": "notebook:get-kernel", + "label": "Get Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:hide-all-cell-code", + "label": "Collapse All Code", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:hide-all-cell-outputs", + "label": "Collapse All Outputs", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:hide-cell-code", + "label": "Collapse Selected Code", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:hide-cell-outputs", + "label": "Collapse Selected Outputs", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:insert-cell-above", + "label": "Insert Cell Above", + "caption": "Insert a cell above", + "shortcuts": [ + "A" + ] + }, + { + "id": "notebook:insert-cell-below", + "label": "Insert Cell Below", + "caption": "Insert a cell below", + "shortcuts": [ + "B" + ] + }, + { + "id": "notebook:insert-heading-above", + "label": "Insert Heading Above Current Heading", + "caption": "", + "shortcuts": [ + "Shift A" + ] + }, + { + "id": "notebook:insert-heading-below", + "label": "Insert Heading Below Current Heading", + "caption": "", + "shortcuts": [ + "Shift B" + ] + }, + { + "id": "notebook:interrupt-kernel", + "label": "Interrupt Kernel", + "caption": "Interrupt the kernel", + "shortcuts": [] + }, + { + "id": "notebook:merge-cell-above", + "label": "Merge Cell Above", + "caption": "", + "shortcuts": [ + "Ctrl Backspace" + ] + }, + { + "id": "notebook:merge-cell-below", + "label": "Merge Cell Below", + "caption": "", + "shortcuts": [ + "Ctrl Shift M" + ] + }, + { + "id": "notebook:merge-cells", + "label": "Merge Selected Cells", + "caption": "", + "shortcuts": [ + "Shift M" + ] + }, + { + "id": "notebook:move-cell-down", + "label": "Move Cell Down", + "caption": "Move this cell down", + "shortcuts": [ + "Ctrl Shift ArrowDown" + ] + }, + { + "id": "notebook:move-cell-up", + "label": "Move Cell Up", + "caption": "Move this cell up", + "shortcuts": [ + "Ctrl Shift ArrowUp" + ] + }, + { + "id": "notebook:move-cursor-down", + "label": "Select Cell Below", + "caption": "", + "shortcuts": [ + "ArrowDown" + ] + }, + { + "id": "notebook:move-cursor-heading-above-or-collapse", + "label": "Select Heading Above or Collapse Heading", + "caption": "", + "shortcuts": [ + "ArrowLeft" + ] + }, + { + "id": "notebook:move-cursor-heading-below-or-expand", + "label": "Select Heading Below or Expand Heading", + "caption": "", + "shortcuts": [ + "ArrowRight" + ] + }, + { + "id": "notebook:move-cursor-up", + "label": "Select Cell Above", + "caption": "", + "shortcuts": [ + "ArrowUp" + ] + }, + { + "id": "notebook:paste-and-replace-cell", + "label": "Paste Cell and Replace", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:paste-cell-above", + "label": "Paste Cell Above", + "caption": "Paste this cell from the clipboard", + "shortcuts": [] + }, + { + "id": "notebook:paste-cell-below", + "label": "Paste Cell Below", + "caption": "Paste this cell from the clipboard", + "shortcuts": [ + "V" + ] + }, + { + "id": "notebook:reconnect-to-kernel", + "label": "Reconnect to Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:redo", + "label": "Redo", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:redo-cell-action", + "label": "Redo Cell Operation", + "caption": "", + "shortcuts": [ + "Shift Z" + ] + }, + { + "id": "notebook:render-all-markdown", + "label": "Render All Markdown Cells", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:replace-selection", + "label": "Replace Selection in Notebook Cell", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:restart-and-run-to-selected", + "label": "Restart Kernel and Run up to Selected Cellâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:restart-clear-output", + "label": "Restart Kernel and Clear Outputs of All Cellsâ€Ļ", + "caption": "Restart the kernel and clear all outputs of all cells", + "shortcuts": [] + }, + { + "id": "notebook:restart-kernel", + "label": "Restart Kernelâ€Ļ", + "caption": "Restart the kernel", + "shortcuts": [] + }, + { + "id": "notebook:restart-run-all", + "label": "Restart Kernel and Run All Cellsâ€Ļ", + "caption": "Restart the kernel and run all cells", + "shortcuts": [] + }, + { + "id": "notebook:run-all-above", + "label": "Run All Above Selected Cell", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:run-all-below", + "label": "Run Selected Cell and All Below", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:run-all-cells", + "label": "Run All Cells", + "caption": "Run all cells", + "shortcuts": [] + }, + { + "id": "notebook:run-cell", + "label": "Run Selected Cell and Do not Advance", + "caption": "", + "shortcuts": [ + "Ctrl Enter" + ] + }, + { + "id": "notebook:run-cell-and-insert-below", + "label": "Run Selected Cell and Insert Below", + "caption": "", + "shortcuts": [ + "Alt Enter" + ] + }, + { + "id": "notebook:run-cell-and-select-next", + "label": "Run Selected Cell", + "caption": "Run this cell and advance", + "shortcuts": [ + "Shift Enter" + ] + }, + { + "id": "notebook:run-in-console", + "label": "Run Selected Text or Current Line in Console", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:select-all", + "label": "Select All Cells", + "caption": "", + "shortcuts": [ + "Ctrl A" + ] + }, + { + "id": "notebook:select-last-run-cell", + "label": "Select current running or last run cell", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:set-side-by-side-ratio", + "label": "Set side-by-side ratio", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:show-all-cell-code", + "label": "Expand All Code", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:show-all-cell-outputs", + "label": "Expand All Outputs", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:show-cell-code", + "label": "Expand Selected Code", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:show-cell-outputs", + "label": "Expand Selected Outputs", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:shutdown-kernel", + "label": "Shut Down Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:split-cell-at-cursor", + "label": "Split Cell", + "caption": "", + "shortcuts": [ + "Ctrl Shift -" + ] + }, + { + "id": "notebook:toggle-all-cell-line-numbers", + "label": "Show Line Numbers", + "caption": "", + "shortcuts": [ + "Shift L" + ] + }, + { + "id": "notebook:toggle-autoclosing-brackets", + "label": "Auto Close Brackets for All Notebook Cell Types", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:toggle-heading-collapse", + "label": "Toggle Collapse Notebook Heading", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:toggle-render-side-by-side-current", + "label": "Render Side-by-Side", + "caption": "", + "shortcuts": [ + "Shift R" + ] + }, + { + "id": "notebook:trust", + "label": "Trust Notebook", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:undo", + "label": "Undo", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:undo-cell-action", + "label": "Undo Cell Operation", + "caption": "", + "shortcuts": [ + "Z" + ] + }, + { + "id": "property-inspector:show-panel", + "label": "Property Inspector", + "caption": "", + "shortcuts": [ + "Ctrl Shift U" + ] + }, + { + "id": "rendermime:handle-local-link", + "label": "Handle Local Link", + "caption": "", + "shortcuts": [] + }, + { + "id": "runmenu:open", + "label": "Open Run Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "runmenu:restart-and-run-all", + "label": "Restart Kernel and Run All", + "caption": "Restart Kernel and Run All", + "shortcuts": [] + }, + { + "id": "runmenu:run", + "label": "Run Selected", + "caption": "Run Selected", + "shortcuts": [ + "Shift Enter" + ] + }, + { + "id": "runmenu:run-all", + "label": "Run All", + "caption": "Run All", + "shortcuts": [] + }, + { + "id": "running:kernel-new-console", + "label": "New Console for Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "running:kernel-new-notebook", + "label": "New Notebook for Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "running:kernel-open-session", + "label": "Unknown Session", + "caption": "", + "shortcuts": [] + }, + { + "id": "running:kernel-shut-down", + "label": "Shut Down Kernel", + "caption": "", + "shortcuts": [] + }, + { + "id": "running:show-panel", + "label": "Sessions and Tabs", + "caption": "", + "shortcuts": [ + "Ctrl Shift B" + ] + }, + { + "id": "settingeditor:open", + "label": "Settings Editor", + "caption": "", + "shortcuts": [ + "Ctrl ," + ] + }, + { + "id": "settingeditor:open-json", + "label": "Advanced Settings Editor", + "caption": "", + "shortcuts": [] + }, + { + "id": "settingeditor:revert", + "label": "Revert User Settings", + "caption": "", + "shortcuts": [] + }, + { + "id": "settingeditor:save", + "label": "Save User Settings", + "caption": "", + "shortcuts": [ + "Ctrl S" + ] + }, + { + "id": "settingsmenu:open", + "label": "Open Settings Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "sidebar:switch", + "label": "Switch Sidebar Side", + "caption": "", + "shortcuts": [] + }, + { + "id": "statusbar:toggle", + "label": "Show Status Bar", + "caption": "", + "shortcuts": [] + }, + { + "id": "tabsmenu:activate-by-id", + "label": "Activate a widget by its `id`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "tabsmenu:activate-previously-used-tab", + "label": "Activate Previously Used Tab", + "caption": "", + "shortcuts": [ + "Ctrl Shift '" + ] + }, + { + "id": "tabsmenu:open", + "label": "Open Tabs Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "terminal:copy", + "label": "Copy", + "caption": "", + "shortcuts": [] + }, + { + "id": "terminal:create-new", + "label": "Terminal", + "caption": "Start a new terminal session", + "shortcuts": [] + }, + { + "id": "terminal:decrease-font", + "label": "Decrease Terminal Font Size", + "caption": "", + "shortcuts": [] + }, + { + "id": "terminal:increase-font", + "label": "Increase Terminal Font Size", + "caption": "", + "shortcuts": [] + }, + { + "id": "terminal:open", + "label": "Open a terminal by its `name`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "terminal:paste", + "label": "Paste", + "caption": "", + "shortcuts": [] + }, + { + "id": "terminal:refresh", + "label": "Refresh Terminal", + "caption": "Refresh the current terminal session", + "shortcuts": [] + }, + { + "id": "terminal:set-theme", + "label": "Set terminal theme to the provided `theme`.", + "caption": "Set the terminal theme", + "shortcuts": [] + }, + { + "id": "terminal:shut-down", + "label": "Shutdown Terminal", + "caption": "", + "shortcuts": [] + }, + { + "id": "toc:display-h1-numbering", + "label": "Show first-level heading number", + "caption": "", + "shortcuts": [] + }, + { + "id": "toc:display-numbering", + "label": "Show heading number in the document", + "caption": "", + "shortcuts": [] + }, + { + "id": "toc:display-outputs-numbering", + "label": "Show output headings", + "caption": "", + "shortcuts": [] + }, + { + "id": "toc:run-cells", + "label": "Select and Run Cell(s) for this Heading", + "caption": "", + "shortcuts": [] + }, + { + "id": "toc:show-panel", + "label": "Table of Contents", + "caption": "", + "shortcuts": [ + "Ctrl Shift K" + ] + }, + { + "id": "toc:toggle-collapse", + "label": "Collapse All Headings", + "caption": "", + "shortcuts": [] + }, + { + "id": "tooltip:dismiss", + "label": "Dismiss the tooltip", + "caption": "", + "shortcuts": [ + "Escape" + ] + }, + { + "id": "tooltip:launch-console", + "label": "Open the tooltip", + "caption": "", + "shortcuts": [ + "Shift Tab" + ] + }, + { + "id": "tooltip:launch-file", + "label": "Open the tooltip", + "caption": "", + "shortcuts": [ + "Shift Tab" + ] + }, + { + "id": "tooltip:launch-notebook", + "label": "Open the tooltip", + "caption": "", + "shortcuts": [ + "Shift Tab" + ] + }, + { + "id": "tsv:go-to-line", + "label": "Go to Line", + "caption": "", + "shortcuts": [] + }, + { + "id": "viewmenu:line-numbering", + "label": "Show Line Numbers", + "caption": "", + "shortcuts": [ + "Shift L" + ] + }, + { + "id": "viewmenu:match-brackets", + "label": "Match Brackets", + "caption": "", + "shortcuts": [] + }, + { + "id": "viewmenu:open", + "label": "Open View Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "viewmenu:word-wrap", + "label": "Wrap Words", + "caption": "", + "shortcuts": [] + }, + { + "id": "workspace-ui:save", + "label": "Save Current Workspace", + "caption": "", + "shortcuts": [] + }, + { + "id": "workspace-ui:save-as", + "label": "Save Current Workspace Asâ€Ļ", + "caption": "", + "shortcuts": [] + } +] diff --git a/galata/test/documentation/customization.test.ts b/galata/test/documentation/customization.test.ts new file mode 100644 index 000000000000..4cd400f0789a --- /dev/null +++ b/galata/test/documentation/customization.test.ts @@ -0,0 +1,280 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; +import { setSidebarWidth } from './utils'; + +test.use({ + autoGoto: false, + mockState: galata.DEFAULT_DOCUMENTATION_STATE, + viewport: { height: 720, width: 1280 } +}); + +test.describe('Default', () => { + test('should use default layout', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.menu.clickMenuItem('File>New>Terminal'); + + await page.waitForSelector('.jp-Terminal'); + + expect(await page.screenshot()).toMatchSnapshot( + 'default-terminal-position-single.png' + ); + }); + + test('should use default toolbars', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Lorenz.ipynb'); + + await page.waitForSelector('div[role="main"] >> text=Lorenz.ipynb'); + + // Wait for kernel to settle on idle + await page + .locator('.jp-DebuggerBugButton[aria-disabled="false"]') + .waitFor(); + await page + .locator('.jp-Notebook-ExecutionIndicator[data-status="idle"]') + .waitFor(); + + expect( + await page + .locator('div[role="main"] >> .jp-NotebookPanel-toolbar') + .screenshot() + ).toMatchSnapshot('default-notebook-toolbar.png'); + }); + + test('should use default menu bar', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.click('text=Tabs'); + + await page.waitForSelector('#jp-mainmenu-tabs'); + + expect( + await page.screenshot({ clip: { x: 0, y: 0, width: 800, height: 200 } }) + ).toMatchSnapshot('default-menu-bar.png'); + }); + + test('should use default context menu', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.click('text=Lorenz.ipynb', { button: 'right' }); + + await page.hover('ul[role="menu"] >> text=New File'); + + expect( + await page.screenshot({ clip: { x: 0, y: 0, width: 500, height: 500 } }) + ).toMatchSnapshot('default-context-menu.png'); + }); +}); + +test.describe('Customized', () => { + test.use({ + mockSettings: { + ...galata.DEFAULT_SETTINGS, + '@jupyterlab/application-extension:context-menu': { + contextMenu: [ + // Disable New notebook entry + { + command: 'notebook:create-new', + selector: '.jp-DirListing-content', + args: { + isContextMenu: true + }, + disabled: true + }, + // Add new entry on notebook file to export them as Markdown + { + command: 'notebook:export-to-format', + selector: '.jp-DirListing-item[data-file-type="notebook"]', + rank: 3, + // Command arguments + args: { + format: 'markdown', + label: 'Export as Markdown' + } + } + ] + }, + '@jupyterlab/application-extension:shell': { + layout: { + single: { + 'Linked Console': { area: 'down' }, + Inspector: { area: 'down' }, + 'Cloned Output': { area: 'down' }, + // Add new terminals in the down area in simple mode + Terminal: { area: 'down' } + }, + multiple: { + // Add new terminals in the right sidebar in default mode + Terminal: { area: 'right' } + } + } + }, + '@jupyterlab/notebook-extension:panel': { + toolbar: [ + // Disable the restart and run all button + { + name: 'restart-and-run', + disabled: true + }, + // Add a new button to clear all cell outputs + { + name: 'clear-all-outputs', + command: 'notebook:clear-all-cell-outputs' + } + ] + }, + '@jupyterlab/mainmenu-extension:plugin': { + menus: [ + { + // Disable the Run menu + id: 'jp-mainmenu-run', + disabled: true + }, + { + // Move the Tabs menu to the end by changing its rank + id: 'jp-mainmenu-tabs', + rank: 1100, + items: [ + // Add a new entry in the Tabs menu + { + command: 'launcher:create', + rank: 0 + } + ] + } + ] + } + } + }); + test('should use customized layout', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.menu.clickMenuItem('File>New>Terminal'); + + await page.waitForSelector('.jp-Terminal'); + + await setSidebarWidth(page, 271, 'right'); + + expect(await page.screenshot()).toMatchSnapshot( + 'customized-terminal-position-single.png' + ); + }); + + test('should use customized toolbars', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Lorenz.ipynb'); + + await page.waitForSelector('div[role="main"] >> text=Lorenz.ipynb'); + + await page.waitForSelector('text=Python 3 (ipykernel) | Idle'); + + expect( + await page + .locator('div[role="main"] >> .jp-NotebookPanel-toolbar') + .screenshot() + ).toMatchSnapshot('customized-notebook-toolbar.png'); + }); + + test('should use customized menu bar', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.click('text=Tabs'); + + await page.waitForSelector('#jp-mainmenu-tabs'); + + expect( + await page.screenshot({ clip: { x: 0, y: 0, width: 800, height: 200 } }) + ).toMatchSnapshot('customized-menu-bar.png'); + }); + + test('should use customized context menu', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.click('text=Lorenz.ipynb', { button: 'right' }); + + await page.hover('ul[role="menu"] >> text=New File'); + + expect( + await page.screenshot({ clip: { x: 0, y: 0, width: 500, height: 500 } }) + ).toMatchSnapshot('customized-context-menu.png'); + }); +}); diff --git a/galata/test/documentation/customization.test.ts-snapshots/customized-context-menu-documentation-linux.png b/galata/test/documentation/customization.test.ts-snapshots/customized-context-menu-documentation-linux.png new file mode 100644 index 000000000000..bfb235fc12b1 Binary files /dev/null and b/galata/test/documentation/customization.test.ts-snapshots/customized-context-menu-documentation-linux.png differ diff --git a/galata/test/documentation/customization.test.ts-snapshots/customized-menu-bar-documentation-linux.png b/galata/test/documentation/customization.test.ts-snapshots/customized-menu-bar-documentation-linux.png new file mode 100644 index 000000000000..be11ef7bd3d0 Binary files /dev/null and b/galata/test/documentation/customization.test.ts-snapshots/customized-menu-bar-documentation-linux.png differ diff --git a/galata/test/documentation/customization.test.ts-snapshots/customized-notebook-toolbar-documentation-linux.png b/galata/test/documentation/customization.test.ts-snapshots/customized-notebook-toolbar-documentation-linux.png new file mode 100644 index 000000000000..be9420f664ad Binary files /dev/null and b/galata/test/documentation/customization.test.ts-snapshots/customized-notebook-toolbar-documentation-linux.png differ diff --git a/galata/test/documentation/customization.test.ts-snapshots/customized-terminal-position-single-documentation-linux.png b/galata/test/documentation/customization.test.ts-snapshots/customized-terminal-position-single-documentation-linux.png new file mode 100644 index 000000000000..b21dc2d44b6f Binary files /dev/null and b/galata/test/documentation/customization.test.ts-snapshots/customized-terminal-position-single-documentation-linux.png differ diff --git a/galata/test/documentation/customization.test.ts-snapshots/default-context-menu-documentation-linux.png b/galata/test/documentation/customization.test.ts-snapshots/default-context-menu-documentation-linux.png new file mode 100644 index 000000000000..976b9b235409 Binary files /dev/null and b/galata/test/documentation/customization.test.ts-snapshots/default-context-menu-documentation-linux.png differ diff --git a/galata/test/documentation/customization.test.ts-snapshots/default-menu-bar-documentation-linux.png b/galata/test/documentation/customization.test.ts-snapshots/default-menu-bar-documentation-linux.png new file mode 100644 index 000000000000..eab33dfdecce Binary files /dev/null and b/galata/test/documentation/customization.test.ts-snapshots/default-menu-bar-documentation-linux.png differ diff --git a/galata/test/documentation/customization.test.ts-snapshots/default-notebook-toolbar-documentation-linux.png b/galata/test/documentation/customization.test.ts-snapshots/default-notebook-toolbar-documentation-linux.png new file mode 100644 index 000000000000..06c693edf915 Binary files /dev/null and b/galata/test/documentation/customization.test.ts-snapshots/default-notebook-toolbar-documentation-linux.png differ diff --git a/galata/test/documentation/customization.test.ts-snapshots/default-terminal-position-single-documentation-linux.png b/galata/test/documentation/customization.test.ts-snapshots/default-terminal-position-single-documentation-linux.png new file mode 100644 index 000000000000..46c3cacade64 Binary files /dev/null and b/galata/test/documentation/customization.test.ts-snapshots/default-terminal-position-single-documentation-linux.png differ diff --git a/galata/test/documentation/data/extensions-search-all.json b/galata/test/documentation/data/extensions-search-all.json new file mode 100644 index 000000000000..5ce569887987 --- /dev/null +++ b/galata/test/documentation/data/extensions-search-all.json @@ -0,0 +1,104 @@ +[ + { + "name": "jupyterlab-git", + "description": "A JupyterLab extension for version control using git", + "homepage_url": "https://github.com/jupyterlab/jupyterlab-git", + "pkg_type": "prebuilt", + "companion": null, + "core": false, + "enabled": false, + "install": null, + "installed": null, + "installed_version": "", + "is_allowed": true, + "latest_version": "0.37.1", + "status": "ok", + "author": "Jupyter Development Team", + "license": "BSD-3-Clause" + }, + { + "name": "jupyterlab-github", + "description": "JupyterLab viewer for GitHub repositories", + "homepage_url": "https://github.com/jupyterlab/jupyterlab-github", + "pkg_type": "prebuilt", + "companion": null, + "core": false, + "enabled": false, + "install": null, + "installed": null, + "installed_version": "", + "is_allowed": true, + "latest_version": "3.0.1", + "status": "ok", + "author": "Anna Smith", + "license": "BSD-3-Clause" + }, + { + "name": "jupyterlab-plugin-graph", + "description": "JupyterLab extension to show an interactive dependency graph of the installed plugins", + "homepage_url": "https://github.com/jupyterlab-contrib/jupyterlab-plugin-graph.git", + "pkg_type": "prebuilt", + "companion": null, + "core": false, + "enabled": false, + "install": null, + "installed": null, + "installed_version": "", + "is_allowed": true, + "latest_version": "0.2.1", + "status": "ok", + "author": "JupyterLab Contrib Team", + "license": "" + }, + { + "name": "jupyterlab-plugin-playground", + "description": "A JupyterLab Plugin Playground.", + "homepage_url": "https://github.com/jupyterlab/jupyterlab-plugin-playground", + "pkg_type": "prebuilt", + "companion": null, + "core": false, + "enabled": false, + "install": null, + "installed": null, + "installed_version": "", + "is_allowed": true, + "latest_version": "0.4.0", + "status": "ok", + "author": "Project Jupyter Contributors", + "license": "BSD-3-Clause" + }, + { + "name": "jupyterlab-pullrequests", + "description": "Pull Requests for JupyterLab", + "homepage_url": "https://github.com/jupyterlab/pull-requests", + "pkg_type": "prebuilt", + "companion": null, + "core": false, + "enabled": false, + "install": null, + "installed": null, + "installed_version": "", + "is_allowed": true, + "latest_version": "3.0.2", + "status": "ok", + "author": "Jupyter Development Team", + "license": "BSD-3-Clause" + }, + { + "name": "jupyterlab-recents", + "description": "Track recent files and folders.", + "homepage_url": "https://github.com/jupyterlab-contrib/jupyterlab-recents", + "pkg_type": "prebuilt", + "companion": null, + "core": false, + "enabled": false, + "install": null, + "installed": null, + "installed_version": "", + "is_allowed": true, + "latest_version": "3.1.0", + "status": "ok", + "author": "John Doe", + "license": "BSD-3-Clause" + } +] diff --git a/galata/test/documentation/data/extensions-search-drawio.json b/galata/test/documentation/data/extensions-search-drawio.json new file mode 100644 index 000000000000..9a1aa38d410a --- /dev/null +++ b/galata/test/documentation/data/extensions-search-drawio.json @@ -0,0 +1,36 @@ +[ + { + "name": "ipydrawio", + "description": "Draw.io Diagrams as Jupyter Widgets", + "homepage_url": "https://ipydrawio.rtfd.io", + "pkg_type": "prebuilt", + "companion": null, + "core": false, + "enabled": false, + "install": null, + "installed": null, + "installed_version": "", + "is_allowed": true, + "latest_version": "1.2.0", + "status": "ok", + "author": "ipydrawio Contributors", + "license": "Apache-2.0" + }, + { + "name": "ipydrawio-export", + "description": "PDF export for Drawio diagrams in JupyterLab", + "homepage_url": "https://ipydrawio.rtfd.io", + "pkg_type": "prebuilt", + "companion": null, + "core": false, + "enabled": false, + "install": null, + "installed": null, + "installed_version": "", + "is_allowed": true, + "latest_version": "1.2.0", + "status": "ok", + "author": "ipydrawio Contributors", + "license": "Apache-2.0" + } +] diff --git a/galata/test/documentation/data/extensions.json b/galata/test/documentation/data/extensions.json new file mode 100644 index 000000000000..53f6b1e34349 --- /dev/null +++ b/galata/test/documentation/data/extensions.json @@ -0,0 +1,38 @@ +[ + { + "name": "@jupyterlab/geojson-extension", + "description": "GeoJSON renderer for JupyterLab", + "homepage_url": "https://github.com/jupyterlab/jupyter-renderers", + "enabled": true, + "core": false, + "latest_version": "3.2.0", + "installed_version": "3.2.0", + "status": "ok", + "pkg_type": "prebuilt", + "is_allowed": true, + "installed": true, + "install": { + "packageManager": "python", + "packageName": "jupyterlab-geojson", + "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package jupyterlab-geojson" + } + }, + { + "name": "@jupyter-widgets/jupyterlab-manager", + "description": "The JupyterLab extension providing Jupyter widgets.", + "homepage_url": "https://github.com/jupyter-widgets/ipywidgets", + "enabled": true, + "core": false, + "latest_version": "3.1.0", + "installed_version": "3.1.0", + "status": "ok", + "pkg_type": "prebuilt", + "is_allowed": true, + "installed": true, + "install": { + "packageManager": "python", + "packageName": "jupyterlab_widgets", + "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package jupyterlab_widgets" + } + } +] diff --git a/galata/test/documentation/data/jupyter.png b/galata/test/documentation/data/jupyter.png new file mode 100644 index 000000000000..c013435c4cf8 Binary files /dev/null and b/galata/test/documentation/data/jupyter.png differ diff --git a/galata/test/documentation/debugger.test.ts b/galata/test/documentation/debugger.test.ts new file mode 100644 index 000000000000..c97a8e6dcf38 --- /dev/null +++ b/galata/test/documentation/debugger.test.ts @@ -0,0 +1,358 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { + expect, + galata, + IJupyterLabPageFixture, + test +} from '@jupyterlab/galata'; +import { positionMouseOver, setSidebarWidth } from './utils'; + +test.use({ + autoGoto: false, + mockState: galata.DEFAULT_DOCUMENTATION_STATE, + viewport: { height: 720, width: 1280 } +}); + +test.describe('Debugger', () => { + test('Kernel capability', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + // Wait for kernel to settle on idle + await page + .locator('.jp-DebuggerBugButton[aria-disabled="false"]') + .waitFor(); + await page + .locator('.jp-Notebook-ExecutionIndicator[data-status="idle"]') + .waitFor(); + + expect( + await page.screenshot({ + clip: { x: 1030, y: 62, width: 210, height: 28 } + }) + ).toMatchSnapshot('debugger_kernel.png'); + }); + + test('Activate', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await setSidebarWidth(page, 251, 'right'); + + expect( + await page.screenshot({ clip: { y: 62, x: 780, width: 210, height: 28 } }) + ).toMatchSnapshot('debugger_activate.png'); + }); + + test('Set breakpoint', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await setSidebarWidth(page, 251, 'right'); + + await setBreakpoint(page); + + // Wait for breakpoint to finish appearing + await page.waitForTimeout(150); + + expect( + await page.screenshot({ + clip: { y: 100, x: 300, width: 300, height: 80 } + }) + ).toMatchSnapshot('debugger_breakpoint.png'); + }); + + test('Highlight run cell button', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + const runButton = await page.waitForSelector( + '.jp-Toolbar-item >> [data-command="notebook:run-cell-and-select-next"]' + ); + + // Inject mouse pointer + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [await positionMouseOver(runButton)] + ); + await runButton.focus(); + await runButton.hover(); + + expect( + await page.screenshot({ clip: { y: 62, x: 400, width: 190, height: 60 } }) + ).toMatchSnapshot('debugger_run.png'); + }); + + test('Stop on breakpoint', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await setSidebarWidth(page, 251, 'right'); + + await setBreakpoint(page); + + // Don't wait as it will be blocked + void page.notebook.runCell(1); + + // Wait to be stopped on the breakpoint + await page.debugger.waitForCallStack(); + + expect( + await page.screenshot({ + clip: { y: 100, x: 300, width: 300, height: 80 } + }) + ).toMatchSnapshot('debugger_stop_on_breakpoint.png'); + + await page.click('button[title^=Continue]'); + }); + + test('Breakpoints on exception', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await setSidebarWidth(page, 251, 'right'); + + await expect(page.locator('button.jp-PauseOnExceptions')).not.toHaveClass( + /lm-mod-toggled/ + ); + await page.locator('button.jp-PauseOnExceptions').click(); + const menu = page.locator('.jp-PauseOnExceptions-menu'); + await expect(menu).toBeVisible(); + await expect(menu.locator('li.lm-Menu-item')).toHaveCount(3); + await expect(menu.locator('li.lm-Menu-item.lm-mod-toggled')).toHaveCount(0); + + await menu + .locator('li div.lm-Menu-itemLabel:text("userUnhandled")') + .click(); + + await expect(page.locator('button.jp-PauseOnExceptions')).toHaveClass( + /lm-mod-toggled/ + ); + + await page.notebook.enterCellEditingMode(0); + const keyboard = page.keyboard; + await keyboard.press('Control+A'); + await keyboard.type('try:\n1/0\n', { delay: 100 }); + await keyboard.press('Backspace'); + await keyboard.type('except:\n2/0\n', { delay: 100 }); + + void page.notebook.runCell(0); + + // Wait to be stopped on the breakpoint + await page.debugger.waitForCallStack(); + expect( + await page.screenshot({ + clip: { y: 110, x: 300, width: 300, height: 80 } + }) + ).toMatchSnapshot('debugger_stop_on_unhandled_exception.png'); + + await page.click('button[title^=Continue]'); + await page.notebook.waitForRun(0); + + await page.locator('button.jp-PauseOnExceptions').click(); + + await expect(menu.locator('li.lm-Menu-item.lm-mod-toggled')).toHaveCount(1); + await expect( + menu.locator('li:has(div.lm-Menu-itemLabel:text("userUnhandled"))') + ).toHaveClass(/lm-mod-toggled/); + + await menu.locator('li div.lm-Menu-itemLabel:text("raised")').click(); + + void page.notebook.runCell(0); + + // Wait to be stopped on the breakpoint + await page.debugger.waitForCallStack(); + expect( + await page.screenshot({ + clip: { y: 110, x: 300, width: 300, height: 80 } + }) + ).toMatchSnapshot('debugger_stop_on_raised_exception.png'); + await page.click('button[title^=Continue]'); + await page.click('button[title^=Continue]'); + }); + + test('Debugger sidebar', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + const sidebar = await page.waitForSelector( + '[data-id="jp-debugger-sidebar"]' + ); + await sidebar.click(); + await setSidebarWidth(page, 251, 'right'); + + // Inject mouse pointer + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [await positionMouseOver(sidebar, { left: 0.25 })] + ); + + expect( + await page.screenshot({ + clip: { y: 22, x: 1200, width: 85, height: 160 } + }) + ).toMatchSnapshot('debugger_sidebar.png'); + }); + + test('Variables panel', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await setSidebarWidth(page, 251, 'right'); + + await setBreakpoint(page); + + // Don't wait as it will be blocked + void page.notebook.runCell(1); + + // Wait to be stopped on the breakpoint and the local variables to be displayed + await page.debugger.waitForCallStack(); + await expect(page.locator('select[aria-label="Scope"]')).toHaveValue( + 'Locals' + ); + + expect( + await page.screenshot({ + clip: { y: 58, x: 998, width: 280, height: 138 } + }) + ).toMatchSnapshot('debugger_variables.png'); + }); + + test('Call Stack panel', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await setSidebarWidth(page, 251, 'right'); + + await setBreakpoint(page); + + // Don't wait as it will be blocked + void page.notebook.runCell(1); + + // Wait to be stopped on the breakpoint + await page.debugger.waitForCallStack(); + + await expect( + page.locator('[aria-label="side panel content"] >> text=add').first() + ).toBeVisible(); + + // Don't compare screenshot as the kernel id varies + // Need to set precisely the path + await page.screenshot({ + clip: { y: 196, x: 998, width: 280, height: 138 }, + path: 'test/documentation/screenshots/debugger-callstack.png' + }); + + await page.click('button[title^=Continue]'); + }); + + test('Breakpoints panel', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await setSidebarWidth(page, 251, 'right'); + + await setBreakpoint(page); + + // Don't wait as it will be blocked + void page.notebook.runCell(1); + + // Wait to be stopped on the breakpoint + await page.debugger.waitForCallStack(); + + const breakpointsPanel = await page.debugger.getBreakPointsPanel(); + expect(await breakpointsPanel.innerText()).toMatch(/ipykernel.*\/\d+.py/); + + // Don't compare screenshot as the kernel id varies + // Need to set precisely the path + await page.screenshot({ + clip: { y: 334, x: 998, width: 280, height: 138 }, + path: 'test/documentation/screenshots/debugger-breakpoints.png' + }); + + await page.click('button[title^=Continue]'); + }); + + test('Source panel', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await setSidebarWidth(page, 251, 'right'); + + await setBreakpoint(page); + + // Don't wait as it will be blocked + void page.notebook.runCell(1); + + // Wait to be stopped on the breakpoint + await page.debugger.waitForCallStack(); + + await expect( + page.locator( + '[aria-label="side panel content"] >> text=Source/tmp/ipykernel_' + ) + ).toBeVisible(); + + // Don't compare screenshot as the kernel id varies + // Need to set precisely the path + await page.screenshot({ + clip: { y: 478, x: 998, width: 280, height: 138 }, + path: 'test/documentation/screenshots/debugger-source.png' + }); + + await page.click('button[title^=Continue]'); + }); +}); + +async function createNotebook(page: IJupyterLabPageFixture) { + await page.notebook.createNew(); + + await setSidebarWidth(page); + + await page.waitForSelector('text=Python 3 (ipykernel) | Idle'); +} + +async function setBreakpoint(page: IJupyterLabPageFixture) { + await page.notebook.setCell( + 0, + 'code', + 'def add(a, b):\nres = a + b\nreturn res' + ); + await page.notebook.run(); + await page.notebook.addCell('code', 'result = add(1, 2)\nprint(result)'); + + await page.notebook.clickCellGutter(0, 2); +} diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-activate-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-activate-documentation-linux.png new file mode 100644 index 000000000000..100ecd5a5d54 Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-activate-documentation-linux.png differ diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-breakpoint-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-breakpoint-documentation-linux.png new file mode 100644 index 000000000000..2b4b4439d989 Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-breakpoint-documentation-linux.png differ diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-kernel-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-kernel-documentation-linux.png new file mode 100644 index 000000000000..a8f46c5b9f8b Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-kernel-documentation-linux.png differ diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-run-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-run-documentation-linux.png new file mode 100644 index 000000000000..1a6e543ff9a6 Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-run-documentation-linux.png differ diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-sidebar-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-sidebar-documentation-linux.png new file mode 100644 index 000000000000..66d0439de4cc Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-sidebar-documentation-linux.png differ diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-breakpoint-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-breakpoint-documentation-linux.png new file mode 100644 index 000000000000..e2ed22072ab7 Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-breakpoint-documentation-linux.png differ diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-raised-exception-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-raised-exception-documentation-linux.png new file mode 100644 index 000000000000..4024680093df Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-raised-exception-documentation-linux.png differ diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-unhandled-exception-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-unhandled-exception-documentation-linux.png new file mode 100644 index 000000000000..e9e48d34ad4d Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-stop-on-unhandled-exception-documentation-linux.png differ diff --git a/galata/test/documentation/debugger.test.ts-snapshots/debugger-variables-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-variables-documentation-linux.png new file mode 100644 index 000000000000..649d9324aad9 Binary files /dev/null and b/galata/test/documentation/debugger.test.ts-snapshots/debugger-variables-documentation-linux.png differ diff --git a/galata/test/documentation/export_notebook.test.ts b/galata/test/documentation/export_notebook.test.ts new file mode 100644 index 000000000000..69792ccbf73b --- /dev/null +++ b/galata/test/documentation/export_notebook.test.ts @@ -0,0 +1,77 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; +import { setSidebarWidth } from './utils'; + +test.use({ + autoGoto: false, + mockState: galata.DEFAULT_DOCUMENTATION_STATE, + viewport: { height: 720, width: 1280 } +}); + +test.describe('Export Notebook', () => { + test('Export Menu', async ({ page }) => { + await page.goto(); + + await setSidebarWidth(page); + + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Lorenz.ipynb'); + + await page.waitForSelector('text=Python 3 (ipykernel) | Idle'); + + await page.click('text=File'); + await page.click( + '.lm-Menu ul[role="menu"] >> text=Save and Export Notebook As' + ); + + // Wait for Latex renderer + // note: requires the a11y/assistive-mml MathJax extension + await page.waitForSelector('text=(Īƒ, β, Ī)'); + + expect( + await page.screenshot({ clip: { y: 5, x: 0, width: 700, height: 700 } }) + ).toMatchSnapshot('exporting_menu.png'); + }); + + test('Slides', async ({ page }) => { + await page.goto(); + + await setSidebarWidth(page); + + await page + .locator('[aria-label="File Browser Section"]') + .getByText('notebooks') + .dblclick(); + await page.getByText('Lorenz.ipynb').dblclick(); + + await page.getByText('Python 3 (ipykernel) | Idle').waitFor(); + + await page.getByTitle('Property Inspector').click(); + + await page + .locator('.jp-PropertyInspector') + .getByText('Common Tools') + .click(); + + await page + .locator('.jp-ActiveCellTool') + .getByText(/# The Lorenz/) + .waitFor(); + + await page + .locator( + '#jp-MetadataForm-\\@jupyterlab\\/notebook-extension\\:tools_\\/slideshow\\/slide_type' + ) + .selectOption({ label: 'Slide' }); + // Wait for Latex renderer + await page.getByText('(Īƒ, β, Ī)').waitFor(); + + expect( + await page.screenshot({ clip: { y: 5, x: 283, width: 997, height: 400 } }) + ).toMatchSnapshot('exporting_slide_type.png'); + }); +}); diff --git a/galata/test/documentation/export_notebook.test.ts-snapshots/exporting-menu-documentation-linux.png b/galata/test/documentation/export_notebook.test.ts-snapshots/exporting-menu-documentation-linux.png new file mode 100644 index 000000000000..67856a882885 Binary files /dev/null and b/galata/test/documentation/export_notebook.test.ts-snapshots/exporting-menu-documentation-linux.png differ diff --git a/galata/test/documentation/export_notebook.test.ts-snapshots/exporting-slide-type-documentation-linux.png b/galata/test/documentation/export_notebook.test.ts-snapshots/exporting-slide-type-documentation-linux.png new file mode 100644 index 000000000000..1f33adcc6b11 Binary files /dev/null and b/galata/test/documentation/export_notebook.test.ts-snapshots/exporting-slide-type-documentation-linux.png differ diff --git a/galata/test/documentation/extension_manager.test.ts b/galata/test/documentation/extension_manager.test.ts new file mode 100644 index 000000000000..23e058a2f52b --- /dev/null +++ b/galata/test/documentation/extension_manager.test.ts @@ -0,0 +1,180 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { + expect, + galata, + IJupyterLabPageFixture, + test +} from '@jupyterlab/galata'; +import { setSidebarWidth, stubGitHubUserIcons } from './utils'; +import { default as extensionsList } from './data/extensions.json'; +import { default as allExtensionsList } from './data/extensions-search-all.json'; +import { default as drawioExtensionsList } from './data/extensions-search-drawio.json'; +import { JSONExt } from '@lumino/coreutils'; + +test.use({ + autoGoto: false, + mockState: galata.DEFAULT_DOCUMENTATION_STATE, + viewport: { height: 720, width: 1280 } +}); + +test.describe('Extension Manager', () => { + test.beforeEach(async ({ page }) => { + // Mock get extensions list + await page.route(galata.Routes.extensions, async (route, request) => { + const url = request.url(); + switch (request.method()) { + case 'GET': + if (!url.includes('query')) { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(extensionsList) + }); + } else if (url.includes('query=drawio')) { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(drawioExtensionsList) + }); + } else { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(allExtensionsList) + }); + } + default: + return route.continue(); + } + }); + }); + + test('Sidebar', async ({ page }) => { + await page.goto(); + await openExtensionSidebar(page); + + expect( + await page.screenshot({ clip: { y: 31, x: 0, width: 283, height: 600 } }) + ).toMatchSnapshot('extensions_default.png'); + }); + + test('Warning', async ({ page }) => { + await page.goto(); + + await page.click('[title="Extension Manager"]'); + expect( + await page.screenshot({ clip: { y: 31, x: 0, width: 283, height: 400 } }) + ).toMatchSnapshot('extensions_disabled.png'); + }); + + test('Warning acknowledge', async ({ page }) => { + await page.goto(); + + await openExtensionSidebar(page); + + expect( + await page.screenshot({ clip: { y: 31, x: 0, width: 283, height: 400 } }) + ).toMatchSnapshot('extensions_enabled.png'); + }); + + test('Search', async ({ page }) => { + await stubGitHubUserIcons(page); + + await page.goto(); + + await openExtensionSidebar(page); + + await page.fill( + '.jp-extensionmanager-view >> [placeholder="Search"]', + 'drawio' + ); + + await page.evaluate(() => { + (document.activeElement as HTMLElement).blur(); + }); + + // We can not wait for extension kept by the keyword as they are already in the DOM + await page.waitForSelector('text=No entries'); + + expect( + await page.screenshot({ clip: { y: 31, x: 0, width: 283, height: 600 } }) + ).toMatchSnapshot('extensions_search.png'); + }); +}); + +test.describe('Filtered Extension Manager', () => { + test('Blocked installed extension', async ({ page }) => { + // Mock get extensions list + const extensions = JSONExt.deepCopy(extensionsList); + extensions[0]['is_allowed'] = false; + await page.route(galata.Routes.extensions, async (route, request) => { + switch (request.method()) { + case 'GET': + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(extensions) + }); + default: + return route.continue(); + } + }); + await page.goto(); + + await openExtensionSidebar(page); + + expect( + await page.screenshot({ + clip: { x: 33, y: 100, width: 250, height: 280 } + }) + ).toMatchSnapshot('extensions_blocked_list.png'); + }); + + test('Allowed installed extension', async ({ page }) => { + // Mock get extensions list + const extensions = JSONExt.deepCopy(extensionsList); + extensions[1]['is_allowed'] = false; + await page.route(galata.Routes.extensions, async (route, request) => { + switch (request.method()) { + case 'GET': + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(extensions) + }); + default: + return route.continue(); + } + }); + await page.goto(); + + await openExtensionSidebar(page); + + expect( + await page.screenshot({ + clip: { x: 33, y: 100, width: 250, height: 280 } + }) + ).toMatchSnapshot('extensions_allowed_list.png'); + }); +}); + +async function openExtensionSidebar(page: IJupyterLabPageFixture) { + await page.click('[title="Extension Manager"]'); + + await Promise.all([ + page.waitForResponse(new RegExp(`${galata.Routes.extensions}?refresh=0`)), + page.waitForResponse( + new RegExp( + `${galata.Routes.extensions}?query&page=1&per_page=30&refresh=0` + ) + ), + page.click('button:has-text("Yes")') + ]); + await page.waitForSelector( + '.jp-extensionmanager-view >> .jp-AccordionPanel-title[aria-expanded="false"] >> text=Warning' + ); + + await setSidebarWidth(page); +} diff --git a/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-allowed-list-documentation-linux.png b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-allowed-list-documentation-linux.png new file mode 100644 index 000000000000..ef8dbd063373 Binary files /dev/null and b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-allowed-list-documentation-linux.png differ diff --git a/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-blocked-list-documentation-linux.png b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-blocked-list-documentation-linux.png new file mode 100644 index 000000000000..ef8dbd063373 Binary files /dev/null and b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-blocked-list-documentation-linux.png differ diff --git a/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-default-documentation-linux.png b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-default-documentation-linux.png new file mode 100644 index 000000000000..8aeed42f5711 Binary files /dev/null and b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-default-documentation-linux.png differ diff --git a/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-disabled-documentation-linux.png b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-disabled-documentation-linux.png new file mode 100644 index 000000000000..dc7caad5ab8f Binary files /dev/null and b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-disabled-documentation-linux.png differ diff --git a/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-enabled-documentation-linux.png b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-enabled-documentation-linux.png new file mode 100644 index 000000000000..0a1bc2deb42b Binary files /dev/null and b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-enabled-documentation-linux.png differ diff --git a/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-search-documentation-linux.png b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-search-documentation-linux.png new file mode 100644 index 000000000000..cc9341ae255a Binary files /dev/null and b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-search-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts b/galata/test/documentation/general.test.ts new file mode 100644 index 000000000000..6687ef44dcee --- /dev/null +++ b/galata/test/documentation/general.test.ts @@ -0,0 +1,776 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; +import { + generateArrow, + positionMouse, + positionMouseOver, + setSidebarWidth +} from './utils'; + +test.use({ + autoGoto: false, + mockState: galata.DEFAULT_DOCUMENTATION_STATE, + viewport: { height: 720, width: 1280 } +}); + +test.describe('General', () => { + test('Welcome', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + // README.md in preview + await page.click('text=README.md', { + button: 'right' + }); + await page.click('text=Open With'); + await page.click('text=Markdown Preview'); + + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Lorenz.ipynb'); + + await page.click('text=File'); + await page.click('.lm-Menu ul[role="menu"] >> text=New'); + await page.click('#jp-mainmenu-file-new >> text=Terminal'); + + await page.click('text=File'); + await page.click('.lm-Menu ul[role="menu"] >> text=New'); + await page.click('#jp-mainmenu-file-new >> text=Console'); + await page.click('button:has-text("Select")'); + + await page.dblclick('text=Data.ipynb'); + + await page.dblclick('text=lorenz.py'); + + await page.click('div[role="main"] >> text=Lorenz.ipynb'); + + await page.notebook.run(); + + const cell = await page.$( + '[aria-label="Code Cell Content with Output"] >> text=interactive' + ); + await cell.click(); + await page.keyboard.press('ContextMenu'); + await page.click('text=Create New View for Cell Output'); + + // Emulate drag and drop + const viewerHandle = await page.$('div[role="main"] >> text=lorenz.py'); + await viewerHandle.click(); + const viewerBBox = await viewerHandle.boundingBox(); + + await page.mouse.move( + viewerBBox.x + 0.5 * viewerBBox.width, + viewerBBox.y + 0.5 * viewerBBox.height + ); + await page.mouse.down(); + await page.mouse.move(viewerBBox.x + 0.5 * viewerBBox.width, 600); + await page.mouse.up(); + + expect(await page.screenshot()).toMatchSnapshot('jupyterlab.png'); + }); + + test('Overview', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await openOverview(page); + + expect(await page.screenshot()).toMatchSnapshot('interface_jupyterlab.png'); + }); + + test('Left Sidebar', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.dblclick('[aria-label="File Browser Section"] >> text=data'); + + await page.evaluate(() => { + (document.activeElement as HTMLElement).blur(); + }); + + expect( + await page.screenshot({ clip: { y: 31, x: 0, width: 283, height: 400 } }) + ).toMatchSnapshot('interface_left.png'); + }); + + test('Right Sidebar', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await page.notebook.createNew(); + await page.click('[title="Property Inspector"]'); + await setSidebarWidth(page, 251, 'right'); + + expect( + await page.screenshot({ + clip: { y: 32, x: 997, width: 283, height: 400 } + }) + ).toMatchSnapshot('interface_right.png'); + + await page.click('.jp-PropertyInspector >> text=Common Tools'); + + await expect( + page.locator('.jp-ActiveCellTool .jp-InputPrompt') + ).not.toBeEmpty(); + await expect( + page.locator('.jp-ActiveCellTool .jp-InputPrompt') + ).not.toHaveClass(/lm-mod-hidden/); + + expect( + await page.screenshot({ + clip: { y: 32, x: 997, width: 283, height: 400 } + }) + ).toMatchSnapshot('interface_right_common.png'); + + // Expect the 'Raw NbConvert Format' field to be displayed only on raw cells + await expect( + page.locator( + '.jp-NotebookTools-tool .jp-FormGroup-fieldLabel:text("Raw NBConvert Format")' + ) + ).toHaveCount(0); + await page.notebook.addCell('raw', 'Raw cell'); + await expect( + page.locator( + '.jp-NotebookTools-tool .jp-FormGroup-fieldLabel:text("Raw NBConvert Format")' + ) + ).toHaveCount(1); + + // Open Advanced tools and get metadata content + await page.click('.jp-PropertyInspector >> text=Advanced Tools'); + await expect( + page.locator('.jp-MetadataForm .jp-MetadataEditorTool') + ).toHaveCount(2); + const cellMetadata = await page + .locator('.jp-MetadataForm .jp-MetadataEditorTool') + .first() + .textContent(); + const notebookMetadata = await page + .locator('.jp-MetadataForm .jp-MetadataEditorTool') + .last() + .textContent(); + expect(cellMetadata).toContain('"tags": []'); + expect(notebookMetadata).not.toContain('"base_numbering"'); + + // Expect adding tag is reflected in CellMetadataEditor + await page.click('.jp-CellTags .jp-CellTags-Add'); + await page.keyboard.type('test-tag'); + await page.keyboard.press('Enter'); + await expect( + page.locator('.jp-CellTags .jp-CellTags-Holder span').first() + ).toHaveText('test-tag'); + + const newCellMetadata = ( + await page + .locator('.jp-MetadataForm .jp-MetadataEditorTool') + .first() + .textContent() + )?.replace(/\s/g, ''); + expect(newCellMetadata).toContain('"tags":["test-tag"]'); + + // Expect modifying 'toc base number' value is reflected in NotebookMetadataEditor + await page + .locator('.jp-MetadataForm input[label="Table of content - Base number"]') + .fill('3'); + const newNotebookMetadata = ( + await page + .locator('.jp-MetadataForm .jp-MetadataEditorTool') + .last() + .textContent() + )?.replace(/\s/g, ''); + expect(newNotebookMetadata).toContain('"base_numbering":3'); + + // Test the active cell widget + await expect( + page.locator('.jp-ActiveCellTool .jp-ActiveCellTool-Content pre') + ).toHaveText('Raw cell'); + await expect( + page.locator('.jp-ActiveCellTool .jp-InputPrompt') + ).toHaveClass(/lm-mod-hidden/); + await (await page.notebook.getCellInput(1))?.click(); + await page.keyboard.type(' content'); + await expect( + page.locator('.jp-ActiveCellTool .jp-ActiveCellTool-Content pre') + ).toHaveText('Raw cell content'); + + await page.notebook.addCell('code', 'print("test")'); + await expect( + page.locator('.jp-ActiveCellTool .jp-ActiveCellTool-Content pre') + ).toHaveText('print("test")'); + await expect( + page.locator('.jp-ActiveCellTool .jp-InputPrompt') + ).not.toHaveClass(/lm-mod-hidden/); + await expect(page.locator('.jp-ActiveCellTool .jp-InputPrompt')).toHaveText( + '[ ]:' + ); + + await page.notebook.runCell(2, true); + await expect(page.locator('.jp-ActiveCellTool .jp-InputPrompt')).toHaveText( + '[1]:' + ); + }); + + test('Open tabs', async ({ page }) => { + await openOverview(page); + + await page.click('[title="Running Terminals and Kernels"]'); + + await page + .locator( + '.jp-RunningSessions-item.jp-mod-kernel >> text="Python 3 (ipykernel)"' + ) + .waitFor(); + expect( + await page.screenshot({ clip: { y: 27, x: 0, width: 283, height: 400 } }) + ).toMatchSnapshot('interface_tabs.png'); + }); + + test('Tabs menu', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await openOverview(page); + + await page.click('text="Tabs"'); + + expect( + await page.screenshot({ clip: { y: 0, x: 210, width: 700, height: 350 } }) + ).toMatchSnapshot('interface_tabs_menu.png'); + }); + + test('File menu', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + // Hide file browser + await page.click('[title^="File Browser"]'); + + // Inject arrow + await page.evaluate( + ([arrow]) => { + document.body.insertAdjacentHTML('beforeend', arrow); + }, + [generateArrow({ x: 50, y: 55 }, -30)] + ); + + expect( + await page.screenshot({ clip: { y: 27, x: 0, width: 283, height: 400 } }) + ).toMatchSnapshot('files_menu_left.png'); + }); + + test('File New menu', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + // Hide file browser + await page.click('[title^="File Browser"]'); + + await page.click('text=File'); + await page.mouse.move(70, 40); + const fileMenuNewItem = await page.waitForSelector( + '.lm-Menu ul[role="menu"] >> text=New' + ); + await fileMenuNewItem.click(); + + // Inject mouse + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [ + await positionMouseOver(fileMenuNewItem, { + left: 0, + // small negative offset to place the cursor before "New" + offsetLeft: -17, + top: 0.5 + }) + ] + ); + + expect( + await page.screenshot({ clip: { y: 0, x: 0, width: 620, height: 400 } }) + ).toMatchSnapshot('files_menu_top.png'); + }); + + test('Shareable link', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + + await page.click('text=Lorenz.ipynb', { button: 'right' }); + await page.hover('text=Copy Shareable Link'); + + const itemHandle = await page.$('text=Copy Shareable Link'); + + // Inject mouse + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [await positionMouseOver(itemHandle, { top: 0.5, left: 0.55 })] + ); + + expect( + await page.screenshot({ clip: { y: 0, x: 0, width: 500, height: 500 } }) + ).toMatchSnapshot('files_shareable_link.png'); + }); + + test('File New Text file', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + // Hide file browser + await page.click('[title^="File Browser"]'); + + await page.click('text=File'); + await page.mouse.move(70, 40); + await page.click('.lm-Menu ul[role="menu"] >> text=New'); + await page.hover('.lm-Menu ul[role="menu"] >> text=Text File'); + + // Inject mouse + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [positionMouse({ x: 500, y: 110 })] + ); + + expect( + await page.screenshot({ clip: { y: 0, x: 0, width: 620, height: 400 } }) + ).toMatchSnapshot('files_create_text_file.png'); + }); + + test('Text Editor Overview', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + // Open jupyterlab.md + await page.dblclick( + '[aria-label="File Browser Section"] >> text=narrative' + ); + await page.dblclick('text=jupyterlab.md'); + + // Hide file browser + await page.click('[title^="File Browser"]'); + + expect(await page.screenshot()).toMatchSnapshot('file_editor_overview.png'); + }); + + test('Text Editor Settings', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + // Open jupyterlab.md + await page.dblclick( + '[aria-label="File Browser Section"] >> text=narrative' + ); + await page.dblclick('text=jupyterlab.md'); + + await page.click('text=Settings'); + await page.click( + '.lm-Menu ul[role="menu"] >> text=Text Editor Indentation' + ); + + expect( + await page.screenshot({ clip: { y: 0, x: 260, width: 600, height: 450 } }) + ).toMatchSnapshot('file_editor_settings.png'); + }); + + test('Notebook', async ({ page }, testInfo) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + // Open Data.ipynb + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Data.ipynb'); + await page.menu.clickMenuItem('Edit>Clear Outputs of All Cells'); + await page.notebook.setCell( + 1, + 'code', + "import pandas\ndf = pandas.read_csv('../data/iris.csv')\ndf.head(5)" + ); + await page.notebook.setCell( + 3, + 'code', + "import json\nfrom IPython.display import GeoJSON\nwith open('../data/Museums_in_DC.geojson') as f:\ns = GeoJSON(json.load(f), layer_options={'minZoom': 11})" + ); + await page.notebook.run(); + + if (testInfo.config.updateSnapshots !== 'none') { + // Wait a bit for the map to load when updating the snapshots + await page.waitForTimeout(300); + } + + // Relax threshold as displayed map may change a bit (in particular text positioning) + expect(await page.screenshot()).toMatchSnapshot('notebook_ui.png', { + maxDiffPixelRatio: 0.02 + }); + }); + + test('Trust indicator', async ({ page }) => { + await page.goto(); + // Open Data.ipynb which is not trusted by default + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Data.ipynb'); + + const trustIndictor = page.locator('.jp-StatusItem-trust'); + + expect(await trustIndictor.screenshot()).toMatchSnapshot( + 'notebook_not_trusted.png' + ); + + // Open trust dialog + // Note: we do not `await` here as it only resolves once dialog is closed + const trustPromise = page.evaluate(() => { + return window.jupyterapp.commands.execute('notebook:trust'); + }); + const dialogSelector = '.jp-Dialog-content'; + await page.waitForSelector(dialogSelector); + // Accept option to trust the notebook + await page.click('.jp-Dialog-button.jp-mod-accept'); + // Wait until dialog is gone + await trustPromise; + + expect(await trustIndictor.screenshot()).toMatchSnapshot( + 'notebook_trusted.png' + ); + }); + + test('Heading anchor', async ({ page }, testInfo) => { + await page.goto(); + await setSidebarWidth(page); + + // Open Data.ipynb + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Data.ipynb'); + + const heading = await page.waitForSelector( + 'h2[id="Open-a-CSV-file-using-Pandas"]' + ); + const anchor = await heading.$('text=Âļ'); + await heading.hover(); + + // Get parent cell which includes the heading + const cell = await heading.evaluateHandle(node => node.closest('.jp-Cell')); + + // Inject mouse + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [ + await positionMouseOver(anchor, { + left: 1, + offsetLeft: 5, + top: 0.25 + }) + ] + ); + + expect(await cell.screenshot()).toMatchSnapshot( + 'notebook_heading_anchor_link.png' + ); + }); + + test('Terminals', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + // Open Data.ipynb + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Data.ipynb'); + + // Open a terminal + await page.click('text=File'); + await page.click('.lm-Menu ul[role="menu"] >> text=New'); + await page.click('#jp-mainmenu-file-new >> text=Terminal'); + + // Wait for the xterm.js element to be added in the DOM + await page.waitForSelector('.jp-Terminal-body'); + + await page.keyboard.type('cd $JUPYTERLAB_GALATA_ROOT_DIR'); + await page.keyboard.press('Enter'); + await page.keyboard.type('tree . -L 2'); + await page.keyboard.press('Enter'); + + // Wait for command answer + await page.waitForTimeout(200); + + expect(await page.screenshot()).toMatchSnapshot('terminal_layout.png'); + }); + + test('Kernels and Terminals', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + // Open a terminal + await page.click('text=File'); + await page.click('.lm-Menu ul[role="menu"] >> text=New'); + await page.click('#jp-mainmenu-file-new >> text=Terminal'); + + await page.dblclick( + '[aria-label="File Browser Section"] >> text=notebooks' + ); + await page.dblclick('text=Data.ipynb'); + await page.dblclick('text=Julia.ipynb'); + + await page.click('[title="Running Terminals and Kernels"]'); + + await expect( + page.locator( + '.jp-RunningSessions-item.jp-mod-kernel >> text="Python 3 (ipykernel)"' + ) + ).toHaveCount(2); + + expect( + await page.screenshot({ clip: { y: 27, x: 0, width: 283, height: 400 } }) + ).toMatchSnapshot('running_layout.png'); + }); + + test('Command Palette', async ({ page }) => { + await page.goto(); + + await page.keyboard.press('Control+Shift+C'); + + expect( + await (await page.$('#modal-command-palette')).screenshot() + ).toMatchSnapshot('command_palette.png'); + }); + + test('Keyboard Shortcuts Help', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await page.notebook.createNew(); + + await page.keyboard.press('Control+Shift+H'); + + expect(await page.locator('.jp-Notebook').screenshot()).toMatchSnapshot( + 'shortcuts_help.png' + ); + }); + + test('Open With', async ({ page }) => { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + await page.click('text=README.md', { + button: 'right' + }); + await page.click('text=Open With'); + await page.hover('text=Markdown Preview'); + + expect( + await page.screenshot({ clip: { y: 0, x: 0, width: 700, height: 500 } }) + ).toMatchSnapshot('file_formats_open_with.png'); + }); + + test('HTML Display', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + // Hide file browser + await page.click('[title^="File Browser"]'); + + await page.notebook.createNew(); + await page.notebook.setCell( + 0, + 'code', + "from IPython.display import display, HTML\ndisplay(HTML('

    Hello World

    '))" + ); + + await page.notebook.run(); + + await page.click('text=File'); + await page.click( + '.lm-Menu ul[role="menu"] >> text=New Console for Notebook' + ); + + await page.click('.jp-CodeConsole-input >> .cm-content'); + await page.keyboard.type( + "from IPython.display import display, HTML\ndisplay(HTML('

    Hello World

    '))" + ); + await page.keyboard.press('Shift+Enter'); + + expect(await page.screenshot()).toMatchSnapshot( + 'file_formats_html_display.png' + ); + }); + + test('Altair', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + // Hide file browser + await page.click('[title^="File Browser"]'); + + await page.notebook.createNew(); + await page.notebook.setCell( + 0, + 'code', + "import altair as alt\n# load a simple dataset as a pandas DataFrame\nfrom vega_datasets import data\ncars = data.cars()\n\nalt.Chart(cars).mark_point().encode(x='Horsepower', y='Miles_per_Gallon', color='Origin').interactive()" + ); + + await page.notebook.run(); + + // Need to wait for altair to update the canvas + await page.waitForSelector('summary'); + + // The menu button '...' color of Altair is flaky increase threshold tolerance + expect(await page.screenshot()).toMatchSnapshot('file_formats_altair.png', { + threshold: 0.3 + }); + }); +}); + +async function openOverview(page) { + await page.goto(); + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + await setSidebarWidth(page); + + // Open Data.ipynb + await page.dblclick('[aria-label="File Browser Section"] >> text=notebooks'); + await page.dblclick('text=Data.ipynb'); + + // Back home + await page.click('.jp-BreadCrumbs-home svg'); + + // Open jupyterlab.md + await page.dblclick('[aria-label="File Browser Section"] >> text=narrative'); + await page.click('text=jupyterlab.md', { + button: 'right' + }); + await page.click('text=Open With'); + await page.click('text=Markdown Preview'); + + // Back home + await page.click('.jp-BreadCrumbs-home svg'); + + // Open bar.vl.json + await page.dblclick('[aria-label="File Browser Section"] >> text=data'); + await page.dblclick('text=bar.vl.json'); + await page.dblclick( + 'text=1024px-Hubble_Interacting_Galaxy_AM_0500-620_(2008-04-24).jpg' + ); + + // Move notebook panel + const notebookHandle = await page.$('div[role="main"] >> text=Data.ipynb'); + await notebookHandle.click(); + const notebookBBox = await notebookHandle.boundingBox(); + + await page.mouse.move( + notebookBBox.x + 0.5 * notebookBBox.width, + notebookBBox.y + 0.5 * notebookBBox.height + ); + await page.mouse.down(); + await page.mouse.move(notebookBBox.x + 0.5 * notebookBBox.width, 350); + await page.mouse.up(); + + // Move md panel + const mdHandle = await page.$('div[role="main"] >> text=jupyterlab.md'); + await mdHandle.click(); + const mdBBox = await mdHandle.boundingBox(); + const panelHandle = await page.activity.getPanel(); + const panelBBox = await panelHandle.boundingBox(); + + await page.mouse.move( + mdBBox.x + 0.5 * mdBBox.width, + mdBBox.y + 0.5 * mdBBox.height + ); + await page.mouse.down(); + await page.mouse.move(panelBBox.x + 0.5 * panelBBox.width, 200); + await page.mouse.up(); +} diff --git a/galata/test/documentation/general.test.ts-snapshots/command-palette-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/command-palette-documentation-linux.png new file mode 100644 index 000000000000..c41a1d4b5695 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/command-palette-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/file-editor-overview-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/file-editor-overview-documentation-linux.png new file mode 100644 index 000000000000..71e4f5529bed Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/file-editor-overview-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/file-editor-settings-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/file-editor-settings-documentation-linux.png new file mode 100644 index 000000000000..abad428c3096 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/file-editor-settings-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/file-formats-altair-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/file-formats-altair-documentation-linux.png new file mode 100644 index 000000000000..77fed53ec2e0 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/file-formats-altair-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/file-formats-html-display-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/file-formats-html-display-documentation-linux.png new file mode 100644 index 000000000000..465e90fb4393 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/file-formats-html-display-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/file-formats-open-with-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/file-formats-open-with-documentation-linux.png new file mode 100644 index 000000000000..c7f533197e72 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/file-formats-open-with-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/files-create-text-file-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/files-create-text-file-documentation-linux.png new file mode 100644 index 000000000000..97b2d8b4f55d Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/files-create-text-file-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/files-menu-left-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/files-menu-left-documentation-linux.png new file mode 100644 index 000000000000..dad5c1ad263a Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/files-menu-left-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/files-menu-top-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/files-menu-top-documentation-linux.png new file mode 100644 index 000000000000..91bc32e34b04 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/files-menu-top-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/files-shareable-link-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/files-shareable-link-documentation-linux.png new file mode 100644 index 000000000000..b2b5f2744fea Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/files-shareable-link-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/interface-jupyterlab-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/interface-jupyterlab-documentation-linux.png new file mode 100644 index 000000000000..4bc00deb227e Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/interface-jupyterlab-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/interface-left-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/interface-left-documentation-linux.png new file mode 100644 index 000000000000..2e843c03b7fd Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/interface-left-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/interface-right-common-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/interface-right-common-documentation-linux.png new file mode 100644 index 000000000000..256406a448cf Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/interface-right-common-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/interface-right-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/interface-right-documentation-linux.png new file mode 100644 index 000000000000..ff6c2e571528 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/interface-right-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/interface-tabs-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/interface-tabs-documentation-linux.png new file mode 100644 index 000000000000..2deced34636f Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/interface-tabs-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/interface-tabs-menu-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/interface-tabs-menu-documentation-linux.png new file mode 100644 index 000000000000..d1f59ed4c737 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/interface-tabs-menu-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/jupyterlab-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/jupyterlab-documentation-linux.png new file mode 100644 index 000000000000..bbd20712f85b Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/jupyterlab-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/notebook-heading-anchor-link-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/notebook-heading-anchor-link-documentation-linux.png new file mode 100644 index 000000000000..6dfffdcf4951 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/notebook-heading-anchor-link-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/notebook-not-trusted-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/notebook-not-trusted-documentation-linux.png new file mode 100644 index 000000000000..53b091866e5e Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/notebook-not-trusted-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/notebook-trusted-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/notebook-trusted-documentation-linux.png new file mode 100644 index 000000000000..ff447e49af5a Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/notebook-trusted-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/notebook-ui-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/notebook-ui-documentation-linux.png new file mode 100644 index 000000000000..42a1419957e0 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/notebook-ui-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/running-layout-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/running-layout-documentation-linux.png new file mode 100644 index 000000000000..bdbe4c8334f8 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/running-layout-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/shortcuts-help-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/shortcuts-help-documentation-linux.png new file mode 100644 index 000000000000..cdb557e2261b Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/shortcuts-help-documentation-linux.png differ diff --git a/galata/test/documentation/general.test.ts-snapshots/terminal-layout-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/terminal-layout-documentation-linux.png new file mode 100644 index 000000000000..436e095be6b2 Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/terminal-layout-documentation-linux.png differ diff --git a/galata/test/documentation/internationalization.test.ts b/galata/test/documentation/internationalization.test.ts new file mode 100644 index 000000000000..5b001631a745 --- /dev/null +++ b/galata/test/documentation/internationalization.test.ts @@ -0,0 +1,74 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; +import { setSidebarWidth } from './utils'; + +test.use({ + autoGoto: false, + mockState: galata.DEFAULT_DOCUMENTATION_STATE, + viewport: { height: 720, width: 1280 } +}); + +test.describe('Internationalization', () => { + test('Menu', async ({ page }) => { + await page.goto(); + + await setSidebarWidth(page); + + await page.click('text=Settings'); + await page.click('.lm-Menu ul[role="menu"] >> text=Language'); + + expect( + await page.screenshot({ clip: { y: 5, x: 250, width: 800, height: 600 } }) + ).toMatchSnapshot('language_settings.png'); + }); + + test('Confirm language', async ({ page }) => { + await page.goto(); + + await setSidebarWidth(page); + + await page.click('text=Settings'); + await page.click('.lm-Menu ul[role="menu"] >> text=Language'); + await page.click('#jp-mainmenu-settings-language >> text=Chinese'); + + expect( + await page.screenshot({ + clip: { y: 200, x: 350, width: 600, height: 300 } + }) + ).toMatchSnapshot('language_change.png'); + }); + + test('UI in Chinese', async ({ page }) => { + await galata.Mock.freezeContentLastModified(page); + await page.goto(); + + await page.click('text=Settings'); + await page.click('.lm-Menu ul[role="menu"] >> text=Language'); + await page.click('#jp-mainmenu-settings-language >> text=Chinese'); + + await Promise.all([ + page.waitForNavigation(), + page.waitForSelector('#jupyterlab-splash'), + page.click('button:has-text("Change and reload")') + ]); + + await page.waitForSelector('#jupyterlab-splash', { + state: 'detached' + }); + + await page.addStyleTag({ + content: `.jp-LabShell.jp-mod-devMode { + border-top: none; + }` + }); + + // Wait for the launcher to be loaded + await page.waitForSelector('text=README.md'); + + await setSidebarWidth(page); + + expect(await page.screenshot()).toMatchSnapshot('language_chinese.png'); + }); +}); diff --git a/galata/test/documentation/internationalization.test.ts-snapshots/language-change-documentation-linux.png b/galata/test/documentation/internationalization.test.ts-snapshots/language-change-documentation-linux.png new file mode 100644 index 000000000000..6921fc9768bd Binary files /dev/null and b/galata/test/documentation/internationalization.test.ts-snapshots/language-change-documentation-linux.png differ diff --git a/galata/test/documentation/internationalization.test.ts-snapshots/language-chinese-documentation-linux.png b/galata/test/documentation/internationalization.test.ts-snapshots/language-chinese-documentation-linux.png new file mode 100644 index 000000000000..6fd310cd7649 Binary files /dev/null and b/galata/test/documentation/internationalization.test.ts-snapshots/language-chinese-documentation-linux.png differ diff --git a/galata/test/documentation/internationalization.test.ts-snapshots/language-settings-documentation-linux.png b/galata/test/documentation/internationalization.test.ts-snapshots/language-settings-documentation-linux.png new file mode 100644 index 000000000000..48ab68ab41fe Binary files /dev/null and b/galata/test/documentation/internationalization.test.ts-snapshots/language-settings-documentation-linux.png differ diff --git a/galata/test/documentation/plugins.test.ts b/galata/test/documentation/plugins.test.ts new file mode 100644 index 000000000000..464cffa58f69 --- /dev/null +++ b/galata/test/documentation/plugins.test.ts @@ -0,0 +1,69 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { test } from '@jupyterlab/galata'; +import { Token } from '@lumino/coreutils'; +import { expect } from '@playwright/test'; +import * as fs from 'fs-extra'; + +test('All plugins and tokens must have a description', async ({ + page +}, testInfo) => { + const { plugins, tokens } = await page.evaluate(async () => { + // As the test is ran in the documentation environments, some plugins and tokens are not from core. + const IGNORED_PLUGINS = [ + '@jupyterlab/geojson-extension:factory', + '@jupyterlab/galata-extension:helpers' + ]; + + const pluginIDs = window.jupyterapp.listPlugins(); + + const plugins: Record = {}; + const tokens: Record = {}; + pluginIDs.forEach(id => { + if (!id.startsWith('@jupyterlab/') || IGNORED_PLUGINS.includes(id)) { + return; + } + + plugins[id] = window.jupyterapp.getPluginDescription(id); + const plugin = ( + (window.jupyterapp as any)._plugins as Map< + string, + { provides: Token | null } + > + ).get(id); + if (plugin?.provides) { + const token = plugin.provides; + tokens[token.name] = token.description; + } + }); + + return Promise.resolve({ plugins, tokens }); + }); + + if (!(await fs.pathExists(testInfo.snapshotDir))) { + await fs.mkdir(testInfo.snapshotDir); + } + await fs.writeJSON(testInfo.snapshotPath('plugins.json'), plugins, { + encoding: 'utf-8', + spaces: 2 + }); + + await fs.writeJSON(testInfo.snapshotPath('tokens.json'), tokens, { + encoding: 'utf-8', + spaces: 2 + }); + + // All plugins must define a description + const missingPluginDescriptions = Object.entries(plugins).filter( + ([id, description]) => !description + ); + // All tokens must define a description + const missingTokenDescriptions = Object.entries(tokens).filter( + ([id, description]) => !description + ); + + // Test against empty list to get directly the plugins/tokens missing description in test output + expect.soft(missingPluginDescriptions).toEqual([]); + expect(missingTokenDescriptions).toEqual([]); +}); diff --git a/galata/test/documentation/plugins.test.ts-snapshots/plugins-documentation-linux.json b/galata/test/documentation/plugins.test.ts-snapshots/plugins-documentation-linux.json new file mode 100644 index 000000000000..08b73cd05b89 --- /dev/null +++ b/galata/test/documentation/plugins.test.ts-snapshots/plugins-documentation-linux.json @@ -0,0 +1,163 @@ +{ + "@jupyterlab/javascript-extension:factory": "Adds renderer for JavaScript content.", + "@jupyterlab/json-extension:factory": "Adds renderer for JSON content.", + "@jupyterlab/json-lines-extension:factory": "Adds renderer for JSONLines content.", + "@jupyterlab/pdf-extension:factory": "Adds renderer for PDF content.", + "@jupyterlab/vega5-extension:factory": "Provides a renderer for Vega 5 and Vega-Lite 3 to 5 content.", + "@jupyterlab/application:mimedocument": "Provides a mime document widget tracker.", + "@jupyterlab/application-extension:context-menu": "Populates the context menu.", + "@jupyterlab/application-extension:dirty": "Adds safeguard dialog when closing the browser tab with unsaved modifications.", + "@jupyterlab/application-extension:main": "Initializes the application and provides the URL tree path handler.", + "@jupyterlab/application-extension:commands": "Adds commands related to the shell.", + "@jupyterlab/application-extension:layout": "Provides the shell layout restorer.", + "@jupyterlab/application-extension:router": "Provides the URL router", + "@jupyterlab/application-extension:tree-resolver": "Provides the tree route resolver", + "@jupyterlab/application-extension:notfound": "Defines the behavior for not found URL (aka route).", + "@jupyterlab/application-extension:faviconbusy": "Handles the favicon depending on the application status.", + "@jupyterlab/application-extension:shell": "Provides the JupyterLab shell. It has an extended API compared to `app.shell`.", + "@jupyterlab/application-extension:status": "Provides the application status.", + "@jupyterlab/application-extension:info": "Provides the application information.", + "@jupyterlab/application-extension:mode-switch": "Adds the interface mode switch", + "@jupyterlab/application-extension:paths": "Provides the application paths.", + "@jupyterlab/application-extension:property-inspector": "Provides the property inspector.", + "@jupyterlab/application-extension:logo": "Sets the application logo.", + "@jupyterlab/application-extension:top-bar": "Adds a toolbar to the top area (next to the main menu bar).", + "@jupyterlab/apputils-extension:announcements": "Add the announcement feature. It will fetch news on the internet and check for application updates.", + "@jupyterlab/apputils-extension:kernel-status": "Provides the kernel status indicator model.", + "@jupyterlab/apputils-extension:notification": "Add the notification center and its status indicator.", + "@jupyterlab/apputils-extension:palette": "Provides the command palette.", + "@jupyterlab/apputils-extension:palette-restorer": "Restores the command palette.", + "@jupyterlab/apputils-extension:print": "Add the print capability", + "@jupyterlab/apputils-extension:resolver": "Provides the window name resolver.", + "@jupyterlab/apputils-extension:running-sessions-status": "Add the running sessions and terminals status bar item.", + "@jupyterlab/apputils-extension:sanitizer": "Provides the HTML sanitizer.", + "@jupyterlab/apputils-extension:settings": "Provides the setting registry.", + "@jupyterlab/apputils-extension:state": "Provides the application state. It is stored per workspaces.", + "@jupyterlab/apputils-extension:splash": "Provides the splash screen.", + "@jupyterlab/apputils-extension:sessionDialogs": "Provides the session context dialogs.", + "@jupyterlab/apputils-extension:themes": "Provides the theme manager.", + "@jupyterlab/apputils-extension:themes-palette-menu": "Adds theme commands to the menu and the command palette.", + "@jupyterlab/apputils-extension:toggle-header": "Adds a command to display the main area widget content header.", + "@jupyterlab/apputils-extension:toolbar-registry": "Provides toolbar items registry.", + "@jupyterlab/apputils-extension:utilityCommands": "Adds meta commands to run set of other commands.", + "@jupyterlab/apputils-extension:workspaces": "Add workspace file type and commands.", + "@jupyterlab/cell-toolbar-extension:plugin": "Add the cells toolbar.", + "@jupyterlab/celltags-extension:plugin": "Adds the cell tags editor.", + "@jupyterlab/codemirror-extension:languages": "Provides the CodeMirror languages registry.", + "@jupyterlab/codemirror-extension:themes": "Provides the CodeMirror theme registry", + "@jupyterlab/codemirror-extension:binding": "Register the CodeMirror extension factory binding the editor and the shared model.", + "@jupyterlab/codemirror-extension:extensions": "Provides the CodeMirror extension factory registry.", + "@jupyterlab/codemirror-extension:services": "Provides the service to instantiate CodeMirror editors.", + "@jupyterlab/codemirror-extension:line-col-status": "Provides the code editor cursor position model.", + "@jupyterlab/completer-extension:manager": "Provides the completion provider manager.", + "@jupyterlab/completer-extension:base-service": "Adds context and kernel completion providers.", + "@jupyterlab/console-extension:factory": "Provides the console widget content factory.", + "@jupyterlab/console-extension:tracker": "Provides the console widget tracker.", + "@jupyterlab/console-extension:foreign": "Add foreign handler of IOPub messages to the console.", + "@jupyterlab/console-extension:kernel-status": "Adds the console to the kernel status indicator model.", + "@jupyterlab/console-extension:cursor-position": "Adds the console to the code editor cursor position model.", + "@jupyterlab/console-extension:completer": "Adds completion to the console.", + "@jupyterlab/csvviewer-extension:csv": "Adds viewer for CSV file types", + "@jupyterlab/csvviewer-extension:tsv": "Adds viewer for TSV file types.", + "@jupyterlab/debugger-extension:service": "Provides the debugger service.", + "@jupyterlab/debugger-extension:consoles": "Add debugger capability to the consoles.", + "@jupyterlab/debugger-extension:files": "Adds debugger capabilities to files.", + "@jupyterlab/debugger-extension:notebooks": "Adds debugger capability to notebooks and provides the debugger notebook handler.", + "@jupyterlab/debugger-extension:variables": "Adds variables renderer and inspection in the debugger variable panel.", + "@jupyterlab/debugger-extension:sidebar": "Provides the debugger sidebar.", + "@jupyterlab/debugger-extension:main": "Initialize the debugger user interface.", + "@jupyterlab/debugger-extension:sources": "Provides the source feature for debugging", + "@jupyterlab/debugger-extension:config": "Provides the debugger configuration", + "@jupyterlab/docmanager-extension:manager": "Provides the document manager.", + "@jupyterlab/docmanager-extension:plugin": "Adds commands and settings to the document manager.", + "@jupyterlab/docmanager-extension:contexts": "Adds the handling of opened documents dirty state.", + "@jupyterlab/docmanager-extension:path-status": "Adds a file path indicator in the status bar.", + "@jupyterlab/docmanager-extension:saving-status": "Adds a saving status indicator.", + "@jupyterlab/docmanager-extension:download": "Adds command to download files.", + "@jupyterlab/docmanager-extension:open-browser-tab": "Adds command to open a browser tab.", + "@jupyterlab/docmanager-extension:opener": "Provides the widget opener.", + "@jupyterlab/documentsearch-extension:plugin": "Provides the document search registry.", + "@jupyterlab/documentsearch-extension:labShellWidgetListener": "Active search on valid document", + "@jupyterlab/extensionmanager-extension:plugin": "Adds the extension manager plugin.", + "@jupyterlab/filebrowser-extension:factory": "Provides the file browser factory.", + "@jupyterlab/filebrowser-extension:default-file-browser": "Provides the default file browser", + "@jupyterlab/filebrowser-extension:browser": "Set up the default file browser (commands, settings,...).", + "@jupyterlab/filebrowser-extension:share-file": "Adds the \"Copy Shareable Link\" command; useful for JupyterHub deployment for example.", + "@jupyterlab/filebrowser-extension:file-upload-status": "Adds a file upload status widget.", + "@jupyterlab/filebrowser-extension:download": "Adds the download file commands. Disabling this plugin will NOT disable downloading files from the server, if the user enters the appropriate download URLs.", + "@jupyterlab/filebrowser-extension:widget": "Adds the file browser to the application shell.", + "@jupyterlab/filebrowser-extension:open-with": "Adds the open-with feature allowing an user to pick the non-preferred document viewer.", + "@jupyterlab/filebrowser-extension:open-browser-tab": "Adds the open-in-new-browser-tab features.", + "@jupyterlab/filebrowser-extension:open-url": "Adds the feature \"Open files from remote URLs\".", + "@jupyterlab/fileeditor-extension:plugin": "Provides the file editor widget tracker.", + "@jupyterlab/fileeditor-extension:cursor-position": "Adds a file editor cursor position status widget.", + "@jupyterlab/fileeditor-extension:completer": "Adds the completer capability to the file editor.", + "@jupyterlab/fileeditor-extension:language-server": "Adds Language Server capability to the file editor.", + "@jupyterlab/fileeditor-extension:search": "Adds search capability to the file editor.", + "@jupyterlab/fileeditor-extension:editor-syntax-status": "Adds a file editor syntax status widget.", + "@jupyterlab/fileeditor-extension:tab-space-status": "Adds a file editor indentation status widget.", + "@jupyterlab/help-extension:about": "Adds a \"About\" dialog feature.", + "@jupyterlab/help-extension:jupyter-forum": "Adds command to open the Jupyter Forum website.", + "@jupyterlab/help-extension:open": "Add command to open websites as panel or browser tab.", + "@jupyterlab/help-extension:resources": "Adds menu entries to Jupyter reference documentation websites.", + "@jupyterlab/help-extension:licenses": "Adds licenses used report tools.", + "@jupyterlab/htmlviewer-extension:plugin": "Adds HTML file viewer and provides its tracker.", + "@jupyterlab/hub-extension:plugin": "Registers commands related to the hub server", + "@jupyterlab/hub-extension:menu": "Adds hub related commands to the menu.", + "@jupyterlab/hub-extension:connectionlost": "Provides a service to be notified when the connection to the hub server is lost.", + "@jupyterlab/imageviewer-extension:plugin": "Adds image viewer and provide its tracker.", + "@jupyterlab/inspector-extension:inspector": "Provides the code introspection widget.", + "@jupyterlab/inspector-extension:consoles": "Adds code introspection support to consoles.", + "@jupyterlab/inspector-extension:notebooks": "Adds code introspection to notebooks.", + "@jupyterlab/launcher-extension:plugin": "Provides the launcher tab service.", + "@jupyterlab/logconsole-extension:plugin": "Provides the logger registry.", + "@jupyterlab/lsp-extension:plugin": "Provides the language server connection manager.", + "@jupyterlab/lsp-extension:feature": "Provides the language server feature manager.", + "@jupyterlab/lsp-extension:settings": "Provides the language server settings.", + "@jupyterlab/lsp:ILSPCodeExtractorsManager": "Provides the code extractor manager.", + "@jupyterlab/mainmenu-extension:plugin": "Adds and provides the application main menu.", + "@jupyterlab/markdownviewer-extension:plugin": "Adds markdown file viewer and provides its tracker.", + "@jupyterlab/markedparser-extension:plugin": "Provides the Markdown parser.", + "@jupyterlab/mathjax-extension:plugin": "Provides the LaTeX mathematical expression interpreter.", + "@jupyterlab/metadataform-extension:metadataforms": "Provides the metadata form registry.", + "@jupyterlab/notebook-extension:factory": "Provides the notebook cell factory.", + "@jupyterlab/notebook-extension:tracker": "Provides the notebook widget tracker.", + "@jupyterlab/notebook-extension:execution-indicator": "Adds a notebook execution status widget.", + "@jupyterlab/notebook-extension:export": "Adds the export notebook commands.", + "@jupyterlab/notebook-extension:tools": "Provides the notebook tools.", + "@jupyterlab/notebook-extension:mode-status": "Adds a notebook mode status widget.", + "@jupyterlab/notebook-extension:trust-status": "Adds the notebook trusted status widget.", + "@jupyterlab/notebook-extension:widget-factory": "Provides the notebook widget factory.", + "@jupyterlab/notebook-extension:log-output": "Adds cell outputs log to the application logger.", + "@jupyterlab/notebook-extension:cloned-outputs": "Adds the clone output feature.", + "@jupyterlab/notebook-extension:code-console": "Adds the notebook code consoles features.", + "@jupyterlab/notebook-extension:copy-output": "Adds the copy cell outputs feature.", + "@jupyterlab/notebook-extension:kernel-status": "Adds the notebook kernel status.", + "@jupyterlab/notebook-extension:cursor-position": "Adds the notebook cursor position status.", + "@jupyterlab/notebook-extension:completer": "Adds the code completion capability to notebooks.", + "@jupyterlab/notebook-extension:search": "Adds search capability to notebooks.", + "@jupyterlab/notebook-extension:toc": "Adds table of content capability to the notebooks", + "@jupyterlab/notebook-extension:language-server": "Adds language server capability to the notebooks.", + "@jupyterlab/notebook-extension:update-raw-mimetype": "Adds metadata form editor for raw cell mimetype.", + "@jupyterlab/notebook-extension:metadata-editor": "Adds metadata form for full metadata editor.", + "@jupyterlab/notebook-extension:active-cell-tool": "Adds active cell field in the metadata editor tab.", + "@jupyterlab/rendermime-extension:plugin": "Provides the render mime registry.", + "@jupyterlab/running-extension:plugin": "Provides the running session managers.", + "@jupyterlab/settingeditor-extension:form-ui": "Adds the interactive settings editor and provides its tracker.", + "@jupyterlab/settingeditor-extension:plugin": "Adds the JSON settings editor and provides its tracker.", + "@jupyterlab/shortcuts-extension:shortcuts": "Adds the keyboard shortcuts editor.", + "@jupyterlab/statusbar-extension:plugin": "Provides the application status bar.", + "@jupyterlab/terminal-extension:plugin": "Adds terminal and provides its tracker.", + "@jupyterlab/theme-dark-extension:plugin": "Adds a dark theme.", + "@jupyterlab/theme-light-extension:plugin": "Adds a light theme.", + "@jupyterlab/toc-extension:registry": "Provides the table of contents registry.", + "@jupyterlab/toc-extension:tracker": "Adds the table of content widget and provides its tracker.", + "@jupyterlab/tooltip-extension:manager": "Provides the tooltip manager.", + "@jupyterlab/tooltip-extension:consoles": "Adds the tooltip capability to consoles.", + "@jupyterlab/tooltip-extension:notebooks": "Adds the tooltip capability to notebooks.", + "@jupyterlab/tooltip-extension:files": "Adds the tooltip capability to file editors.", + "@jupyterlab/translation:translator": "Provides the application translation object.", + "@jupyterlab/translation-extension:plugin": "Adds translation commands and settings.", + "@jupyterlab/ui-components-extension:labicon-manager": "Provides the icon manager.", + "@jupyterlab/ui-components-extension:form-renderer-registry": "Provides the settings form renderer registry." +} diff --git a/galata/test/documentation/plugins.test.ts-snapshots/tokens-documentation-linux.json b/galata/test/documentation/plugins.test.ts-snapshots/tokens-documentation-linux.json new file mode 100644 index 000000000000..3c34091d73fe --- /dev/null +++ b/galata/test/documentation/plugins.test.ts-snapshots/tokens-documentation-linux.json @@ -0,0 +1,72 @@ +{ + "@jupyterlab/application:IMimeDocumentTracker": "A widget tracker for documents rendered using a mime renderer extension. Use this if you want to list and interact with documents rendered by such extensions.", + "@jupyterlab/application:ITreePathUpdater": "A service to update the tree path.", + "@jupyterlab/application:ILayoutRestorer": "A service providing application layout restoration functionality. Use this to have your activities restored across page loads.", + "@jupyterlab/application:IRouter": "The URL router used by the application. Use this to add custom URL-routing for your extension (e.g., to invoke a command if the user navigates to a sub-path).", + "@jupyterlab/application:ITreeResolver": "A service to resolve the tree path.", + "@jupyterlab/application:ILabShell": "A service for interacting with the JupyterLab shell. The top-level ``application`` object also has a reference to the shell, but it has a restricted interface in order to be agnostic to different shell implementations on the application. Use this to get more detailed information about currently active widgets and layout state.", + "@jupyterlab/application:ILabStatus": "A service for interacting with the application busy/dirty\n status. Use this if you want to set the application \"busy\" favicon, or to set\n the application \"dirty\" status, which asks the user for confirmation before leaving the application page.", + "@jupyterlab/application:IInfo": "A service providing metadata about the current application, including disabled extensions and whether dev mode is enabled.", + "@jupyterlab/application:IPaths": "A service providing information about various\n URLs and server paths for the current application. Use this service if you want to\n assemble URLs to use the JupyterLab REST API.", + "@jupyterlab/property-inspector:IPropertyInspectorProvider": "A service to registry new widget in the property inspector side panel.", + "@jupyterlab/apputils:IKernelStatusModel": "A service to register kernel session provider to the kernel status indicator.", + "@jupyterlab/apputils:ICommandPalette": "A service for the application command palette\n in the left panel. Use this to add commands to the palette.", + "@jupyterlab/apputils:IWindowResolver": "A service for a window resolver for the\n application. JupyterLab workspaces are given a name, which are determined using\n the window resolver. Require this if you want to use the name of the current workspace.", + "@jupyterlab/apputils:ISanitizer": "A service for sanitizing HTML strings.", + "@jupyterlab/coreutils:ISettingRegistry": "A service for the JupyterLab settings system.\n Use this if you want to store settings for your application.\n See \"schemaDir\" for more information.", + "@jupyterlab/coreutils:IStateDB": "A service for the JupyterLab state database.\n Use this if you want to store data that will persist across page loads.\n See \"state database\" for more information.", + "@jupyterlab/apputils:ISplashScreen": "A service for the splash screen for the application.\n Use this if you want to show the splash screen for your own purposes.", + "@jupyterlab/apputils:ISessionContextDialogs": "A service for handling the session dialogs.", + "@jupyterlab/apputils:IThemeManager": "A service for the theme manager for the application. This is used primarily in theme extensions to register new themes.", + "@jupyterlab/apputils:IToolbarWidgetRegistry": "A registry for toolbar widgets. Require this\n if you want to build the toolbar dynamically from a data definition (stored in settings for example).", + "@jupyterlab/codemirror:IEditorLanguageRegistry": "A registry for CodeMirror languages.", + "@jupyterlab/codemirror:IEditorThemeRegistry": "A registry for CodeMirror theme.", + "@jupyterlab/codemirror:IEditorExtensionRegistry": "A registry for CodeMirror extension factories.", + "@jupyterlab/codeeditor:IEditorServices": "A service for the text editor provider\n for the application. Use this to create new text editors and host them in your\n UI elements.", + "@jupyterlab/codeeditor:IPositionModel": "A service to handle an code editor cursor position.", + "@jupyterlab/completer:ICompletionProviderManager": "A service for the completion providers management.", + "@jupyterlab/console:IContentFactory": "A factory object that creates new code consoles. Use this if you want to create and host code consoles in your own UI elements.", + "@jupyterlab/console:IConsoleTracker": "A widget tracker for code consoles.\n Use this if you want to be able to iterate over and interact with code consoles\n created by the application.", + "@jupyterlab/debugger:IDebugger": "A debugger user interface.", + "@jupyterlab/debugger:IDebuggerHandler": "A service for handling notebook debugger.", + "@jupyterlab/debugger:IDebuggerSidebar": "A service for the debugger sidebar.", + "@jupyterlab/debugger:IDebuggerSources": "A service to display sources in debug mode.", + "@jupyterlab/debugger:IDebuggerConfig": "A service to handle the debugger configuration.", + "@jupyterlab/docmanager:IDocumentManager": "A service for the manager for all\n documents used by the application. Use this if you want to open and close documents,\n create and delete files, and otherwise interact with the file system.", + "@jupyterlab/docmanager:IDocumentWidgetOpener": "A service to open a widget.", + "@jupyterlab/documentsearch:ISearchProviderRegistry": "A service for a registry of search\n providers for the application. Plugins can register their UI elements with this registry\n to provide find/replace support.", + "@jupyterlab/filebrowser:IFileBrowserFactory": "A factory object that creates file browsers.\n Use this if you want to create your own file browser (e.g., for a custom storage backend),\n or to interact with other file browsers that have been created by extensions.", + "@jupyterlab/filebrowser:IDefaultFileBrowser": "A service for the default file browser.", + "@jupyterlab/filebrowser:IFileBrowserCommands": "A token to ensure file browser commands are loaded.", + "@jupyterlab/fileeditor:IEditorTracker": "A widget tracker for file editors.\n Use this if you want to be able to iterate over and interact with file editors\n created by the application.", + "@jupyterlab/htmlviewer:IHTMLViewerTracker": "A widget tracker for rendered HTML documents.\n Use this if you want to be able to iterate over and interact with HTML documents\n viewed by the application.", + "@jupyterlab/application:IConnectionLost": "A service for invoking the dialog shown\n when JupyterLab has lost its connection to the server. Use this if, for some reason,\n you want to bring up the \"connection lost\" dialog under new circumstances.", + "@jupyterlab/imageviewer:IImageTracker": "A widget tracker for images.\n Use this if you want to be able to iterate over and interact with images\n viewed by the application.", + "@jupyterlab/inspector:IInspector": "A service for adding contextual help to widgets (visible using \"Show Contextual Help\" from the Help menu).\n Use this to hook into the contextual help system in your extension.", + "@jupyterlab/launcher:ILauncher": "A service for the application activity launcher.\n Use this to add your extension activities to the launcher panel.", + "@jupyterlab/logconsole:ILoggerRegistry": "A service providing a logger infrastructure.", + "@jupyterlab/lsp:ILSPDocumentConnectionManager": "Provides the virtual documents and language server connections service.", + "@jupyterlab/lsp:ILSPFeatureManager": "Provides the language server feature manager. This token is required to register new client capabilities.", + "@jupyterlab/lsp:ILSPCodeExtractorsManager": "Provides the code extractor manager. This token is required in your extension to register code extractor allowing the creation of multiple virtual document from an opened document.", + "@jupyterlab/mainmenu:IMainMenu": "A service for the main menu bar for the application.\n Use this if you want to add your own menu items or provide implementations for standardized menu items for specific activities.", + "@jupyterlab/markdownviewer:IMarkdownViewerTracker": "A widget tracker for markdown\n document viewers. Use this if you want to iterate over and interact with rendered markdown documents.", + "@jupyterlab/rendermime:IMarkdownParser": "A service for rendering markdown syntax as HTML content.", + "@jupyterlab/rendermime:ILatexTypesetter": "A service for the LaTeX typesetter for the application. Use this if you want to typeset math in your extension.", + "@jupyterlab/metadataform:IMetadataFormProvider": "A service to register new metadata editor widgets.", + "@jupyterlab/notebook:IContentFactory": "A factory object that creates new notebooks.\n Use this if you want to create and host notebooks in your own UI elements.", + "@jupyterlab/notebook:INotebookTracker": "A widget tracker for notebooks.\n Use this if you want to be able to iterate over and interact with notebooks\n created by the application.", + "@jupyterlab/notebook:INotebookTools": "A service for the \"Notebook Tools\" panel in the\n right sidebar. Use this to add your own functionality to the panel.", + "@jupyterlab/notebook:INotebookWidgetFactory": "A service to create the notebook viewer.", + "@jupyterlab/rendermime:IRenderMimeRegistry": "A service for the rendermime registry for the application. Use this to create renderers for various mime-types in your extension. Many times it will be easier to create a \"mime renderer extension\" rather than using this service directly.", + "@jupyterlab/running:IRunningSessionManagers": "A service to add running session managers.", + "@jupyterlab/settingeditor:ISettingEditorTracker": "A widget tracker for the interactive setting editor.\n Use this if you want to be able to iterate over and interact with setting editors\n created by the application.", + "@jupyterlab/settingeditor:IJSONSettingEditorTracker": "A widget tracker for the JSON setting editor.\n Use this if you want to be able to iterate over and interact with setting editors\n created by the application.", + "@jupyterlab/statusbar:IStatusBar": "A service for the status bar on the application. Use this if you want to add new status bar items.", + "@jupyterlab/terminal:ITerminalTracker": "A widget tracker for terminals.\n Use this if you want to be able to iterate over and interact with terminals\n created by the application.", + "@jupyterlab/toc:ITableOfContentsRegistry": "A service to register table of content factory.", + "@jupyterlab/toc:ITableOfContentsTracker": "A widget tracker for table of contents.", + "@jupyterlab/tooltip:ITooltipManager": "A service for the tooltip manager for the application. Use this to allow your extension to invoke a tooltip.", + "@jupyterlab/translation:ITranslator": "A service to translate strings.", + "@jupyterlab/ui-components:ILabIconManager": "A service to register and request icons.", + "@jupyterlab/ui-components:IFormRendererRegistry": "A service for settings form renderer registration." +} diff --git a/galata/test/documentation/screenshots/debugger-breakpoints.png b/galata/test/documentation/screenshots/debugger-breakpoints.png new file mode 100644 index 000000000000..15ac1f1ad645 Binary files /dev/null and b/galata/test/documentation/screenshots/debugger-breakpoints.png differ diff --git a/galata/test/documentation/screenshots/debugger-callstack.png b/galata/test/documentation/screenshots/debugger-callstack.png new file mode 100644 index 000000000000..7512287e1a9f Binary files /dev/null and b/galata/test/documentation/screenshots/debugger-callstack.png differ diff --git a/galata/test/documentation/screenshots/debugger-source.png b/galata/test/documentation/screenshots/debugger-source.png new file mode 100644 index 000000000000..b8169e512098 Binary files /dev/null and b/galata/test/documentation/screenshots/debugger-source.png differ diff --git a/galata/test/documentation/utils.ts b/galata/test/documentation/utils.ts new file mode 100644 index 000000000000..75aeed354375 --- /dev/null +++ b/galata/test/documentation/utils.ts @@ -0,0 +1,140 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { ElementHandle, Page } from '@playwright/test'; +import fs from 'fs'; +import path from 'path'; + +/** + * Generate a SVG arrow to inject in a HTML document. + * + * @param position Absolute position + * @param rotation Rotation in degree + * @returns The svg to inject in the page + */ +export function generateArrow( + position: { x: number; y: number }, + rotation: number = 0 +): string { + return ` + + + + + + + + + `; +} + +/** + * Generate a SVG mouse pointer to inject in a HTML document. + * + * @param position Absolute position + * @returns The svg to inject in the page + */ +export function positionMouse(position: { x: number; y: number }): string { + // The cursor is CC-0 1.0 from https://github.com/sevmeyer/mocu-xcursor + return ` + + + + + + + +`; +} + +/** + * Position of an injected sprint in a DOM element. + */ +export interface IPositionInElement { + /** + * X-coordinate multiplier for the element's width. + */ + top?: number; + /** + * Y-coordinate multiplier for the element's height. + */ + left?: number; + /** + * Offset added to x-coordinate after calculating position with multipliers. + */ + offsetLeft?: number; + /** + * Offset added to y-coordinate after calculating position with multipliers. + */ + offsetTop?: number; +} + +/** + * Generate a SVG mouse pointer to inject in a HTML document over a DOM element. + * + * @param element A playwright handle for the target DOM element + * @param position A position within the target element (default: bottom right quarter). + * @returns The svg to inject in the page + */ +export async function positionMouseOver( + element: ElementHandle, + position: IPositionInElement = {} +): Promise { + const top = position.top ?? 0.75; + const left = position.left ?? 0.75; + const offsetTop = position.offsetTop ?? 0; + const offsetLeft = position.offsetLeft ?? 0; + const bBox = await element.boundingBox(); + return positionMouse({ + x: bBox.x + bBox.width * left + offsetLeft, + y: bBox.y + bBox.height * top + offsetTop + }); +} + +/** + * Set the sidebar width + * + * @param page Page object + * @param width Sidebar width in pixels + * @param side Which sidebar to set: 'left' or 'right' + */ +export async function setSidebarWidth( + page: Page, + width = 251, + side: 'left' | 'right' = 'left' +): Promise { + const handles = page.locator( + '#jp-main-split-panel > .lm-SplitPanel-handle:not(.lm-mod-hidden)' + ); + const splitHandle = + side === 'left' + ? await handles.first().elementHandle() + : await handles.last().elementHandle(); + const handleBBox = await splitHandle.boundingBox(); + + await page.mouse.move( + handleBBox.x + 0.5 * handleBBox.width, + handleBBox.y + 0.5 * handleBBox.height + ); + await page.mouse.down(); + await page.mouse.move( + side === 'left' ? 33 + width : page.viewportSize().width - 33 - width, + handleBBox.y + 0.5 * handleBBox.height + ); + await page.mouse.up(); +} + +export async function stubGitHubUserIcons(page: Page): Promise { + // stub out github user icons + // only first and last icon for now + // logic in @jupyterlab/extensionmanager/src/models::ListEntry#translateSearchResult + await page.route('https://github.com/*.png*', async (route, request) => { + return route.fulfill({ + status: 200, + contentType: 'image/png', + body: fs.readFileSync(path.resolve(__dirname, './data/jupyter.png')) + }); + }); +} diff --git a/galata/test/galata/benchmarkReporter.spec.ts b/galata/test/galata/benchmarkReporter.spec.ts index 0876948ca088..2f4b46e877f6 100644 --- a/galata/test/galata/benchmarkReporter.spec.ts +++ b/galata/test/galata/benchmarkReporter.spec.ts @@ -117,3 +117,15 @@ test.describe('BenchmarkReporter', () => { expect(figureData).toMatchSnapshot('customized_test.svg'); }); }); + +test.describe('benchmark.distributionChange', () => { + test('matches result from paper', () => { + const change = benchmark.distributionChange( + [7.75, 12.25, 11.5], + [8.75, 6.25, 4.5] + ); + + expect(change.mean).toBeCloseTo(68.3 / 74.5); + expect(change.confidenceInterval).toBeCloseTo(60.2 / 74.5); + }); +}); diff --git a/galata/test/galata/benchmarkReporter.spec.ts-snapshots/customized-test-galata-linux.svg b/galata/test/galata/benchmarkReporter.spec.ts-snapshots/customized-test-galata-linux.svg index eff517054b61..26c84ae858b0 100644 --- a/galata/test/galata/benchmarkReporter.spec.ts-snapshots/customized-test-galata-linux.svg +++ b/galata/test/galata/benchmarkReporter.spec.ts-snapshots/customized-test-galata-linux.svg @@ -1 +1 @@ -Duration of common actions \ No newline at end of file +Duration of common actions \ No newline at end of file diff --git a/galata/test/galata/benchmarkReporter.spec.ts-snapshots/test-galata-linux.svg b/galata/test/galata/benchmarkReporter.spec.ts-snapshots/test-galata-linux.svg index 981a66f4907f..878638393276 100644 --- a/galata/test/galata/benchmarkReporter.spec.ts-snapshots/test-galata-linux.svg +++ b/galata/test/galata/benchmarkReporter.spec.ts-snapshots/test-galata-linux.svg @@ -1 +1 @@ -browseractualexpectedreferencechromium18,204Time (ms)openlarge_code_notebookDuration of common actions \ No newline at end of file +browseractualexpectedreferencechromium18,204Time (ms)openlarge_code_notebookDuration of common actions \ No newline at end of file diff --git a/galata/test/galata/filebrowser.spec.ts b/galata/test/galata/filebrowser.spec.ts new file mode 100644 index 000000000000..b555565f9371 --- /dev/null +++ b/galata/test/galata/filebrowser.spec.ts @@ -0,0 +1,48 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, test } from '@jupyterlab/galata'; + +const DEFAULT_NAME = 'Untitled.ipynb'; + +test.describe('filebrowser helper', () => { + test.beforeEach(async ({ page }) => { + await page.menu.clickMenuItem('File>New>Notebook'); + + await page + .locator('.jp-Dialog') + .getByRole('button', { name: 'Select Kernel', exact: true }) + .click(); + + await page.activity.closeAll(); + }); + + test('should open a file', async ({ page }) => { + await page.filebrowser.open(DEFAULT_NAME); + + expect(await page.activity.isTabActive(DEFAULT_NAME)).toEqual(true); + }); + + test('should activate already opened file', async ({ page }) => { + await page.menu.clickMenuItem('File>New>Console'); + + await page + .locator('.jp-Dialog') + .getByRole('button', { name: 'Select Kernel', exact: true }) + .click(); + + expect.soft(await page.activity.isTabActive(DEFAULT_NAME)).toEqual(false); + await page.filebrowser.open(DEFAULT_NAME); + expect(await page.activity.isTabActive(DEFAULT_NAME)).toEqual(true); + }); + + test('should open the file with another factory', async ({ page }) => { + await page.filebrowser.open(DEFAULT_NAME); + + await page.filebrowser.open(DEFAULT_NAME, 'Editor'); + + await expect( + page.getByRole('main').getByRole('tab', { name: DEFAULT_NAME }) + ).toHaveCount(2); + }); +}); diff --git a/galata/test/galata/fixture.spec.ts b/galata/test/galata/fixture.spec.ts index 20d5a6afe7c0..f23cb2e8fe35 100644 --- a/galata/test/galata/fixture.spec.ts +++ b/galata/test/galata/fixture.spec.ts @@ -16,7 +16,7 @@ test.describe('page', () => { test('should have playwright Page interface', async ({ page }) => { expect(page.waitForSelector).toBe( - ((page as any) as JupyterLabPage).page.waitForSelector + (page as unknown as JupyterLabPage).page.waitForSelector ); }); }); @@ -37,7 +37,7 @@ test.describe('mockSettings', () => { test('should not return mocked settings after save', async ({ page }) => { await page.click('text=Settings'); - await page.click('ul[role="menu"] >> text=Theme'); + await page.click('.lm-Menu ul[role="menu"] >> text=Theme'); const [response] = await Promise.all([ page.waitForResponse( response => @@ -45,7 +45,7 @@ test.describe('mockSettings', () => { response.url() ) && response.request().method() === 'GET' ), - page.click('ul[role="menu"] >> text=JupyterLab Light') + page.click('.lm-Menu ul[role="menu"] >> text=JupyterLab Light') ]); await page.waitForSelector('#jupyterlab-splash', { state: 'detached' }); diff --git a/galata/test/galata/jupyterlabpage.spec.ts b/galata/test/galata/jupyterlabpage.spec.ts index 6490420e86b2..c2081e3a9a50 100644 --- a/galata/test/galata/jupyterlabpage.spec.ts +++ b/galata/test/galata/jupyterlabpage.spec.ts @@ -14,9 +14,9 @@ test.describe('appPath', () => { }); test('should goto the application page and load hook', async ({ page }) => { - expect( - await page.evaluate(() => typeof window.galataip === 'object') - ).toEqual(true); + expect(await page.evaluate(() => typeof window.galata === 'object')).toEqual( + true + ); }); test('should test if the application is in simple mode', async ({ page }) => { @@ -26,15 +26,15 @@ test('should test if the application is in simple mode', async ({ page }) => { test('should reload the application page and load hook', async ({ page }) => { await page.reload(); - expect( - await page.evaluate(() => typeof window.galataip === 'object') - ).toEqual(true); + expect(await page.evaluate(() => typeof window.galata === 'object')).toEqual( + true + ); }); test('should reset the UI', async ({ page }) => { await page.resetUI(); expect(await page.menu.isAnyOpen()).toEqual(false); - expect(await page.waitForSelector(page.launcherSelector)).toBeTruthy(); + await expect(page.launcher).toBeVisible(); expect(await page.kernel.isAnyRunning()).toEqual(false); expect(await page.statusbar.isVisible()).toEqual(true); expect(await page.sidebar.isTabOpen('filebrowser')).toEqual(true); @@ -47,8 +47,205 @@ test('should toggle simple mode', async ({ page }) => { // test that stock playwright test is accessible with page not being JupyterLabPage playwrightTest('should not be loading galata helper', async ({ page }) => { - // eslint-disable-next-line jest/no-standalone-expect expect(page['notebook']).toBeUndefined(); // no helper - // eslint-disable-next-line jest/no-standalone-expect expect(page.url()).toEqual('about:blank'); }); + +test.describe('listeners', () => { + const DEFAULT_NAME = 'untitled.txt'; + + test('should listen to JupyterLab dialog', async ({ page }) => { + await page.evaluate(() => { + window.galata.on('dialog', d => { + // We need to slightly wait before rejecting otherwise + // the `locator('.jp-Dialog').waitFor()` is not resolved. + setTimeout(() => d?.reject(), 100); + }); + }); + + await page.menu.clickMenuItem('File>New>Text File'); + await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); + + await Promise.all([ + page.locator('.jp-Dialog').waitFor(), + page.menu.clickMenuItem('File>Save Text Asâ€Ļ') + ]); + + await expect(page.locator('.jp-Dialog')).toHaveCount(0); + }); + + test('should stop listening to JupyterLab dialog', async ({ page }) => { + await page.evaluate(() => { + const callback = d => { + // We need to slightly wait before rejecting otherwise + // the `locator('.jp-Dialog').waitFor()` is not resolved. + setTimeout(() => d?.reject(), 100); + window.galata.off('dialog', callback); + }; + window.galata.on('dialog', callback); + }); + + await page.menu.clickMenuItem('File>New>Text File'); + await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); + + await Promise.all([ + page.locator('.jp-Dialog').waitFor(), + page.menu.clickMenuItem('File>Save Text Asâ€Ļ') + ]); + + await expect(page.locator('.jp-Dialog')).toHaveCount(0); + + await Promise.all([ + page.locator('.jp-Dialog').waitFor(), + page.menu.clickMenuItem('File>Save Text Asâ€Ļ') + ]); + + await expect(page.locator('.jp-Dialog')).toHaveCount(1); + }); + + test('should listen only once to JupyterLab dialog', async ({ page }) => { + await page.evaluate(() => { + const callback = d => { + // We need to slightly wait before rejecting otherwise + // the `locator('.jp-Dialog').waitFor()` is not resolved. + setTimeout(() => d?.reject(), 100); + }; + window.galata.once('dialog', callback); + }); + + await page.menu.clickMenuItem('File>New>Text File'); + await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); + + await Promise.all([ + page.locator('.jp-Dialog').waitFor(), + page.menu.clickMenuItem('File>Save Text Asâ€Ļ') + ]); + + await expect(page.locator('.jp-Dialog')).toHaveCount(0); + + await Promise.all([ + page.locator('.jp-Dialog').waitFor(), + page.menu.clickMenuItem('File>Save Text Asâ€Ļ') + ]); + + await expect(page.locator('.jp-Dialog')).toHaveCount(1); + }); + + test('should listen to JupyterLab notification', async ({ page }) => { + await page.evaluate(() => { + window.galata.on('notification', n => { + // We need to slightly wait before dismissing otherwise + // the toast is not yet displayed and won't be removed when the notification + // is dismissed. + setTimeout(() => { + void window.jupyterapp.commands.execute( + 'apputils:dismiss-notification', + { + id: n.id + } + ); + }, 100); + }); + }); + + await Promise.all([ + page.locator('.Toastify__toast').waitFor(), + page.evaluate(() => { + void window.jupyterapp.commands.execute('apputils:notify', { + message: 'This is a test message', + options: { autoClose: false } + }); + }) + ]); + await expect(page.locator('.Toastify__toast')).toHaveCount(0); + }); + + test('should stop listening to JupyterLab notification', async ({ page }) => { + await page.evaluate(() => { + const callback = n => { + // We need to slightly wait before dismissing otherwise + // the toast is not yet displayed and won't be removed when the notification + // is dismissed. + setTimeout(() => { + void window.jupyterapp.commands.execute( + 'apputils:dismiss-notification', + { + id: n.id + } + ); + }, 100); + window.galata.off('notification', callback); + }; + window.galata.on('notification', callback); + }); + + await Promise.all([ + page.locator('.Toastify__toast').waitFor(), + page.evaluate(() => { + return window.jupyterapp.commands.execute('apputils:notify', { + message: 'This is a test message', + options: { autoClose: false } + }); + }) + ]); + + await expect(page.locator('.Toastify__toast')).toHaveCount(0); + + await Promise.all([ + page.locator('.Toastify__toast').waitFor(), + page.evaluate(() => { + return window.jupyterapp.commands.execute('apputils:notify', { + message: 'This is a test message', + options: { autoClose: false } + }); + }) + ]); + + await expect(page.locator('.Toastify__toast')).toHaveCount(1); + }); + + test('should listen only once to JupyterLab notification', async ({ + page + }) => { + await page.evaluate(() => { + const callback = n => { + // We need to slightly wait before dismissing otherwise + // the toast is not yet displayed and won't be removed when the notification + // is dismissed. + setTimeout(() => { + void window.jupyterapp.commands.execute( + 'apputils:dismiss-notification', + { + id: n.id + } + ); + }, 100); + }; + window.galata.once('notification', callback); + }); + + await Promise.all([ + page.locator('.Toastify__toast').waitFor(), + page.evaluate(() => { + return window.jupyterapp.commands.execute('apputils:notify', { + message: 'This is a test message', + options: { autoClose: false } + }); + }) + ]); + + await expect(page.locator('.Toastify__toast')).toHaveCount(0); + + await Promise.all([ + page.locator('.Toastify__toast').waitFor(), + page.evaluate(() => { + return window.jupyterapp.commands.execute('apputils:notify', { + message: 'This is a test message', + options: { autoClose: false } + }); + }) + ]); + + await expect(page.locator('.Toastify__toast')).toHaveCount(1); + }); +}); diff --git a/galata/test/galata/notebook.spec.ts b/galata/test/galata/notebook.spec.ts index c04d2c647963..5159400a92d1 100644 --- a/galata/test/galata/notebook.spec.ts +++ b/galata/test/galata/notebook.spec.ts @@ -4,15 +4,13 @@ import * as path from 'path'; -import { expect, test } from '@jupyterlab/galata'; +import { expect, galata, test } from '@jupyterlab/galata'; test.describe('Notebook Tests', () => { test('Create New Notebook', async ({ page, tmpPath }) => { const fileName = 'create_test.ipynb'; await page.notebook.createNew(fileName); - expect( - await page.waitForSelector(`[role="main"] >> text=${fileName}`) - ).toBeTruthy(); + await page.getByRole('main').getByText(fileName).waitFor(); expect(await page.contents.fileExists(`${tmpPath}/${fileName}`)).toEqual( true @@ -27,11 +25,9 @@ test.describe('Notebook Tests', () => { expect(await page.notebook.getCellType(0)).toBe('markdown'); // Wait for kernel to be idle - expect( - await page.waitForSelector(`#jp-main-statusbar >> text=Idle`) - ).toBeTruthy(); + await page.locator('#jp-main-statusbar').getByText('Idle').waitFor(); - expect(await (await page.$('[role="main"]')).screenshot()).toMatchSnapshot( + expect(await page.getByRole('main').screenshot()).toMatchSnapshot( 'markdown-cell.png' ); }); @@ -45,11 +41,11 @@ test.describe('Notebook Tests', () => { // Wait for kernel to be idle and the debug switch to appear await Promise.all([ - page.waitForSelector(`#jp-main-statusbar >> text=Idle`), - page.waitForSelector('.jp-DebuggerBugButton') + page.locator('#jp-main-statusbar').getByText('Idle').waitFor(), + page.locator('.jp-DebuggerBugButton').waitFor() ]); - expect(await (await page.$('[role="main"]')).screenshot()).toMatchSnapshot( + expect(await page.getByRole('main').screenshot()).toMatchSnapshot( 'raw-cell.png' ); }); @@ -62,11 +58,9 @@ test.describe('Notebook Tests', () => { expect(await page.notebook.getCellType(1)).toBe('code'); // Wait for kernel to be idle - expect( - await page.waitForSelector(`#jp-main-statusbar >> text=Idle`) - ).toBeTruthy(); + await page.locator('#jp-main-statusbar').getByText('Idle').waitFor(); - expect(await (await page.$('[role="main"]')).screenshot()).toMatchSnapshot( + expect(await page.getByRole('main').screenshot()).toMatchSnapshot( 'code-cell.png' ); }); @@ -83,7 +77,7 @@ test.describe('Notebook Tests', () => { expect((await page.notebook.getCellTextOutput(2))![0]).toBe('4'); - expect(await (await page.$('[role="main"]')).screenshot()).toMatchSnapshot( + expect(await page.getByRole('main').screenshot()).toMatchSnapshot( 'run-cells.png' ); }); @@ -101,6 +95,8 @@ test.describe('Notebook Tests', () => { await page.notebook.activate(notebook); expect(await page.notebook.isActive(notebook)).toBeTruthy(); + await page.locator('#jp-main-statusbar').getByText('Idle').waitFor(); + await page.notebook.runCellByCell(); const cellOutput2 = await page.notebook.getCellTextOutput(2); @@ -113,7 +109,7 @@ test.describe('Notebook Tests', () => { const panel = await page.activity.getPanel(); - expect(await panel.screenshot()).toMatchSnapshot('example-run.png'); + expect(await panel!.screenshot()).toMatchSnapshot('example-run.png'); }); test('Open folder of notebook and run', async ({ page, tmpPath }) => { @@ -124,13 +120,70 @@ test.describe('Notebook Tests', () => { ); await page.notebook.openByPath(`${tmpPath}/${filename}`); + + await page.locator('#jp-main-statusbar').getByText('Idle').waitFor(); + await page.notebook.runCellByCell(); - expect(await page.waitForSelector('text=100')).toBeTruthy(); + expect(await page.getByText('100').count()).toBeGreaterThanOrEqual(1); await page.notebook.revertChanges(); await page.notebook.close(); - expect(await page.waitForSelector(page.launcherSelector)).toBeTruthy(); + await expect(page.launcher).toBeVisible(); + }); +}); + +test.describe('Access cells in windowed notebook', () => { + test.use({ + mockSettings: { + ...galata.DEFAULT_SETTINGS, + '@jupyterlab/notebook-extension:tracker': { + ...galata.DEFAULT_SETTINGS['@jupyterlab/notebook-extension:tracker'], + windowingMode: 'full' + } + } + }); + + test('get the cell count', async ({ page, tmpPath }) => { + const target = `${tmpPath}/windowed_notebook.ipynb`; + await page.contents.uploadFile( + path.resolve(__dirname, 'notebooks/windowed_notebook.ipynb'), + target + ); + + await page.filebrowser.open(target); + await page.locator('#jp-main-statusbar').getByText('Idle').waitFor(); + + expect(await page.notebook.getCellCount()).toEqual(14); + }); + + test('getCell below the viewport', async ({ page, tmpPath }) => { + const target = `${tmpPath}/windowed_notebook.ipynb`; + await page.contents.uploadFile( + path.resolve(__dirname, 'notebooks/windowed_notebook.ipynb'), + target + ); + + await page.filebrowser.open(target); + await page.locator('#jp-main-statusbar').getByText('Idle').waitFor(); + + expect(await page.notebook.getCell(12)).toBeTruthy(); + }); + + test('getCell above the viewport', async ({ page, tmpPath }) => { + const target = `${tmpPath}/windowed_notebook.ipynb`; + await page.contents.uploadFile( + path.resolve(__dirname, 'notebooks/windowed_notebook.ipynb'), + target + ); + + await page.filebrowser.open(target); + await page.locator('#jp-main-statusbar').getByText('Idle').waitFor(); + await page.waitForTimeout(50); + + await page.notebook.getCell(12); + + expect(await page.notebook.getCell(0)).toBeTruthy(); }); }); diff --git a/galata/test/galata/notebook.spec.ts-snapshots/code-cell-galata-linux.png b/galata/test/galata/notebook.spec.ts-snapshots/code-cell-galata-linux.png index 8cbecf36e91e..0b110ac3a4ea 100644 Binary files a/galata/test/galata/notebook.spec.ts-snapshots/code-cell-galata-linux.png and b/galata/test/galata/notebook.spec.ts-snapshots/code-cell-galata-linux.png differ diff --git a/galata/test/galata/notebook.spec.ts-snapshots/example-run-galata-linux.png b/galata/test/galata/notebook.spec.ts-snapshots/example-run-galata-linux.png index 6713a62a507d..c085580b09f0 100644 Binary files a/galata/test/galata/notebook.spec.ts-snapshots/example-run-galata-linux.png and b/galata/test/galata/notebook.spec.ts-snapshots/example-run-galata-linux.png differ diff --git a/galata/test/galata/notebook.spec.ts-snapshots/markdown-cell-galata-linux.png b/galata/test/galata/notebook.spec.ts-snapshots/markdown-cell-galata-linux.png index e6cbb9baa3fc..39ac67b891c9 100644 Binary files a/galata/test/galata/notebook.spec.ts-snapshots/markdown-cell-galata-linux.png and b/galata/test/galata/notebook.spec.ts-snapshots/markdown-cell-galata-linux.png differ diff --git a/galata/test/galata/notebook.spec.ts-snapshots/raw-cell-galata-linux.png b/galata/test/galata/notebook.spec.ts-snapshots/raw-cell-galata-linux.png index d2fe046fb282..3f7ea71e0ee3 100644 Binary files a/galata/test/galata/notebook.spec.ts-snapshots/raw-cell-galata-linux.png and b/galata/test/galata/notebook.spec.ts-snapshots/raw-cell-galata-linux.png differ diff --git a/galata/test/galata/notebook.spec.ts-snapshots/run-cells-galata-linux.png b/galata/test/galata/notebook.spec.ts-snapshots/run-cells-galata-linux.png index a20d7a81f11f..c2c41a63cf82 100644 Binary files a/galata/test/galata/notebook.spec.ts-snapshots/run-cells-galata-linux.png and b/galata/test/galata/notebook.spec.ts-snapshots/run-cells-galata-linux.png differ diff --git a/galata/test/galata/notebooks/example.ipynb b/galata/test/galata/notebooks/example.ipynb index eca9c71e4eeb..af89605e7879 100644 --- a/galata/test/galata/notebooks/example.ipynb +++ b/galata/test/galata/notebooks/example.ipynb @@ -7,6 +7,7 @@ "outputs": [], "source": [ "from IPython.display import Image\n", + "\n", "Image('./jupyter.png', width=80)" ] }, @@ -40,6 +41,7 @@ "outputs": [], "source": [ "import math\n", + "\n", "math.pi / 2" ] }, diff --git a/galata/test/galata/notebooks/simple_test.ipynb b/galata/test/galata/notebooks/simple_test.ipynb index 809a1be74fbb..57b2ed6a7dbd 100644 --- a/galata/test/galata/notebooks/simple_test.ipynb +++ b/galata/test/galata/notebooks/simple_test.ipynb @@ -19,9 +19,7 @@ "execution_count": 27, "source": [ "from IPython.display import display\n", - "from IPython.display import (\n", - " HTML, Image, Latex, Math, Markdown, SVG\n", - ")" + "from IPython.display import HTML, Image, Latex, Math, Markdown, SVG" ], "outputs": [], "metadata": {} @@ -108,7 +106,9 @@ "cell_type": "code", "execution_count": 30, "source": [ - "import sys; print('this is stderr', file=sys.stderr)" + "import sys\n", + "\n", + "print('this is stderr', file=sys.stderr)" ], "outputs": [ { @@ -232,12 +232,14 @@ "cell_type": "code", "execution_count": 33, "source": [ - "md = Markdown(\"\"\"\n", + "md = Markdown(\n", + " \"\"\"\n", "### Subtitle\n", "\n", "This is some *markdown* text with math $F=ma$.\n", "\n", - "\"\"\")\n", + "\"\"\"\n", + ")\n", "md" ], "outputs": [ @@ -336,13 +338,15 @@ "cell_type": "code", "execution_count": 36, "source": [ - "maxwells = Latex(r\"\"\"\n", + "maxwells = Latex(\n", + " r\"\"\"\n", "\\begin{align}\n", "\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\ \\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n", "\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n", "\\nabla \\cdot \\vec{\\mathbf{B}} & = 0\n", "\\end{align}\n", - "\"\"\")\n", + "\"\"\"\n", + ")\n", "maxwells" ], "outputs": [ @@ -486,4 +490,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/galata/test/galata/notebooks/windowed_notebook.ipynb b/galata/test/galata/notebooks/windowed_notebook.ipynb new file mode 100644 index 000000000000..ad161c3921bc --- /dev/null +++ b/galata/test/galata/notebooks/windowed_notebook.ipynb @@ -0,0 +1,316 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 16, + "id": "4c296a32-1a0c-40e9-8e44-696db2c25eef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "[local link](#Title)" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# dummy\n", + "from IPython.display import Markdown\n", + "\n", + "Markdown('[local link](#Title)')" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "f075900d-442f-40b3-842d-9575568d434b", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import display, HTML\n", + "\n", + "div = HTML('
    ')\n", + "div" + ] + }, + { + "cell_type": "markdown", + "id": "569f59b8-9ffe-47e0-9d39-971da701c380", + "metadata": { + "tags": [] + }, + "source": [ + "# Test JupyterLab windowed notebook" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "e3ba1ca5-8358-462c-bf90-131d6dba9790", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "div" + ] + }, + { + "cell_type": "raw", + "id": "23c8c825-f03f-4039-bf73-74e5a6e21bf3", + "metadata": {}, + "source": [ + "jupyterlab" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cf7edd3c-9499-4301-ad0c-094f18da4d5e", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "application/geo+json": { + "geometry": { + "coordinates": [ + -118.4563712, + 34.0163116 + ], + "type": "Point" + }, + "type": "Feature" + }, + "text/plain": [ + "" + ] + }, + "metadata": { + "application/geo+json": { + "expanded": false, + "root": "root" + } + }, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import GeoJSON\n", + "\n", + "GeoJSON(\n", + " {\"type\": \"Feature\", \"geometry\": {\"type\": \"Point\", \"coordinates\": [-118.4563712, 34.0163116]}}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "352967bc-3746-4333-94ec-23f87fae5763", + "metadata": { + "tags": [] + }, + "source": [ + "## Title" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "40e0425e-3441-4f7f-92b7-56fd2ac6a19d", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello the world\n" + ] + } + ], + "source": [ + "# Drag 1\n", + "print(\"hello the world\")" + ] + }, + { + "cell_type": "raw", + "id": "519597e4-781c-4104-ad4a-2e7dee278e89", + "metadata": {}, + "source": [ + "Drag 2" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "f2fb618b-d6f0-4047-aa02-e75fcea411a2", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A dummy text line\n", + "A dummy text line\n", + "A dummy text line\n", + "A dummy text line\n", + "A dummy text line\n", + "A dummy text line\n", + "A dummy text line\n", + "A dummy text line\n", + "A dummy text line\n", + "A dummy text line\n" + ] + } + ], + "source": [ + "from time import sleep\n", + "\n", + "for i in range(10):\n", + " sleep(1)\n", + " print(\"A dummy text line\")\n", + "# input('Your age')" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "ce7850b3-5d61-4c0c-ae49-32c25da997ef", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "
    " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "div" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "2d4d56bb-ed96-46b9-a647-109971d6fa42", + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import display, IFrame" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "382d7fc0-c55b-4c5e-ae6e-31ee09cab13c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(IFrame('https://jupyterlab.readthedocs.org/', width=600, height=400))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f96e0d00", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/galata/test/galata/test.spec.ts b/galata/test/galata/test.spec.ts index 17bc4b8ae3c7..e8d1fa8b695c 100644 --- a/galata/test/galata/test.spec.ts +++ b/galata/test/galata/test.spec.ts @@ -5,5 +5,5 @@ import { expect, test } from '@jupyterlab/galata'; test('should display the launcher', async ({ page }) => { - expect(await page.waitForSelector(page.launcherSelector)).toBeTruthy(); + await expect(page.launcher).toBeVisible(); }); diff --git a/galata/test/jupyterlab/announcements.test.ts b/galata/test/jupyterlab/announcements.test.ts index fb2c03f1942a..706aa24b4847 100644 --- a/galata/test/jupyterlab/announcements.test.ts +++ b/galata/test/jupyterlab/announcements.test.ts @@ -13,9 +13,7 @@ test.use({ }); test('Announcements requires user agreement', async ({ page }) => { - const notifications = await page.evaluate(() => { - return (window.jupyterapp as any).notificationManager.notifications; - }); + const notifications = await page.notifications; expect(notifications).toHaveLength(1); expect(notifications[0].message).toEqual( @@ -74,12 +72,10 @@ test.describe('Update available', () => { await page.goto(); - const notifications = await page.evaluate(() => { - return (window.jupyterapp as any).notificationManager.notifications; - }); + const notifications = await page.notifications; - const updates = notifications.filter(n => - n.options?.data?.tags?.includes('update') + const updates = notifications.filter( + n => n.options?.data?.tags?.includes('update') ); expect(updates).toHaveLength(1); expect(updates[0].message).toEqual(message); @@ -100,9 +96,7 @@ test.describe('Update available', () => { await page.goto(); - const notifications = await page.evaluate(() => { - return (window.jupyterapp as any).notificationManager.notifications; - }); + const notifications = await page.notifications; expect( notifications.filter(n => n.options?.data?.tags?.includes('update')) @@ -129,9 +123,7 @@ test.describe('Update available', () => { await page.goto(); - const notifications = await page.evaluate(() => { - return (window.jupyterapp as any).notificationManager.notifications; - }); + const notifications = await page.notifications; expect( notifications.filter(n => n.options?.data?.tags?.includes('update')) ).toHaveLength(0); @@ -193,12 +185,10 @@ test.describe('Fetch news', () => { await page.goto(); - const notifications = await page.evaluate(() => { - return (window.jupyterapp as any).notificationManager.notifications; - }); + const notifications = await page.notifications; - const news = notifications.filter(n => - n.options?.data?.tags?.includes('news') + const news = notifications.filter( + n => n.options?.data?.tags?.includes('news') ); expect(news).toHaveLength(2); expect(news.filter(n => n.options.data.id === id)[0].message).toEqual( @@ -222,12 +212,10 @@ test.describe('Fetch news', () => { await page.goto(); - const notifications = await page.evaluate(() => { - return (window.jupyterapp as any).notificationManager.notifications; - }); + const notifications = await page.notifications; - const news = notifications.filter(n => - n.options?.data?.tags?.includes('news') + const news = notifications.filter( + n => n.options?.data?.tags?.includes('news') ); expect(news).toHaveLength(0); }); @@ -251,12 +239,10 @@ test.describe('Fetch news', () => { await page.goto(); - const notifications = await page.evaluate(() => { - return (window.jupyterapp as any).notificationManager.notifications; - }); + const notifications = await page.notifications; - const news = notifications.filter(n => - n.options?.data?.tags?.includes('news') + const news = notifications.filter( + n => n.options?.data?.tags?.includes('news') ); expect(news).toHaveLength(1); expect(news[0].id).not.toEqual(id); diff --git a/galata/test/jupyterlab/cells-motion.spec.ts b/galata/test/jupyterlab/cells-motion.spec.ts new file mode 100644 index 000000000000..10247fdcb608 --- /dev/null +++ b/galata/test/jupyterlab/cells-motion.spec.ts @@ -0,0 +1,170 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, test } from '@jupyterlab/galata'; + +const fileName = 'motion.ipynb'; +const cellSelector = '[role="main"] >> .jp-NotebookPanel >> .jp-Cell'; + +test.beforeEach(async ({ page }) => { + await page.notebook.createNew(fileName); + + // Populate the notebook + await page.notebook.setCell(0, 'markdown', '# Heading 1'); + await page.notebook.addCell('code', '1+1'); + await page.notebook.addCell('markdown', '## Heading 1.1'); + await page.notebook.addCell('code', '2+2'); + await page.notebook.addCell('markdown', '# Heading 2'); + await page.notebook.addCell('code', '3+3'); + + await page.notebook.run(); +}); + +test('Move down a cell', async ({ page }) => { + const content = await page + .locator(`${cellSelector} >> nth=2`) + .allTextContents(); + await page + .locator(`${cellSelector} >> nth=2 >> .jp-InputArea-prompt`) + .click(); + + await page.keyboard.press('Control+Shift+ArrowDown'); + + await expect(page.locator(`${cellSelector} >> nth=3`)).toHaveClass( + /jp-mod-active/ + ); + expect( + await page.locator(`${cellSelector} >> nth=3`).allTextContents() + ).toEqual(content); +}); + +test('Move up a cell', async ({ page }) => { + const content = await page + .locator(`${cellSelector} >> nth=2`) + .allTextContents(); + await page + .locator(`${cellSelector} >> nth=2 >> .jp-InputArea-prompt`) + .click(); + await page.keyboard.press('Control+Shift+ArrowUp'); + + await expect(page.locator(`${cellSelector} >> nth=1`)).toHaveClass( + /jp-mod-active/ + ); + expect( + await page.locator(`${cellSelector} >> nth=1`).allTextContents() + ).toEqual(content); +}); + +test('Move down two cells with first active', async ({ page }) => { + const content1 = await page + .locator(`${cellSelector} >> nth=2`) + .allTextContents(); + const content2 = await page + .locator(`${cellSelector} >> nth=3`) + .allTextContents(); + + await page + .locator(`${cellSelector} >> nth=3 >> .jp-InputArea-prompt`) + .click(); + + await page.keyboard.press('Shift+ArrowUp'); + await page.keyboard.press('Control+Shift+ArrowDown'); + + await expect(page.locator(`${cellSelector} >> nth=3`)).toHaveClass( + /jp-mod-active/ + ); + await expect(page.locator(`${cellSelector} >> nth=4`)).toHaveClass( + /jp-mod-selected/ + ); + expect( + await page.locator(`${cellSelector} >> nth=3`).allTextContents() + ).toEqual(content1); + expect( + await page.locator(`${cellSelector} >> nth=4`).allTextContents() + ).toEqual(content2); +}); + +test('Move up two cells with first active', async ({ page }) => { + const content1 = await page + .locator(`${cellSelector} >> nth=2`) + .allTextContents(); + const content2 = await page + .locator(`${cellSelector} >> nth=3`) + .allTextContents(); + + await page + .locator(`${cellSelector} >> nth=3 >> .jp-InputArea-prompt`) + .click(); + + await page.keyboard.press('Shift+ArrowUp'); + await page.keyboard.press('Control+Shift+ArrowUp'); + + await expect(page.locator(`${cellSelector} >> nth=1`)).toHaveClass( + /jp-mod-active/ + ); + await expect(page.locator(`${cellSelector} >> nth=2`)).toHaveClass( + /jp-mod-selected/ + ); + expect( + await page.locator(`${cellSelector} >> nth=1`).allTextContents() + ).toEqual(content1); + expect( + await page.locator(`${cellSelector} >> nth=2`).allTextContents() + ).toEqual(content2); +}); + +test('Move down two cells with last active', async ({ page }) => { + const content1 = await page + .locator(`${cellSelector} >> nth=2`) + .allTextContents(); + const content2 = await page + .locator(`${cellSelector} >> nth=3`) + .allTextContents(); + + await page + .locator(`${cellSelector} >> nth=2 >> .jp-InputArea-prompt`) + .click(); + await page.keyboard.press('Shift+ArrowDown'); + await page.keyboard.press('Control+Shift+ArrowDown'); + + await expect(page.locator(`${cellSelector} >> nth=3`)).toHaveClass( + /jp-mod-selected/ + ); + await expect(page.locator(`${cellSelector} >> nth=4`)).toHaveClass( + /jp-mod-active/ + ); + expect( + await page.locator(`${cellSelector} >> nth=3`).allTextContents() + ).toEqual(content1); + expect( + await page.locator(`${cellSelector} >> nth=4`).allTextContents() + ).toEqual(content2); +}); + +test('Move up two cells with last active', async ({ page }) => { + const content1 = await page + .locator(`${cellSelector} >> nth=2`) + .allTextContents(); + const content2 = await page + .locator(`${cellSelector} >> nth=3`) + .allTextContents(); + await page + .locator(`${cellSelector} >> nth=2 >> .jp-InputArea-prompt`) + .click(); + + await page.keyboard.press('Shift+ArrowDown'); + await page.keyboard.press('Control+Shift+ArrowDown'); + + await expect(page.locator(`${cellSelector} >> nth=3`)).toHaveClass( + /jp-mod-selected/ + ); + await expect(page.locator(`${cellSelector} >> nth=4`)).toHaveClass( + /jp-mod-active/ + ); + expect( + await page.locator(`${cellSelector} >> nth=3`).allTextContents() + ).toEqual(content1); + expect( + await page.locator(`${cellSelector} >> nth=4`).allTextContents() + ).toEqual(content2); +}); diff --git a/galata/test/jupyterlab/cells.test.ts b/galata/test/jupyterlab/cells.test.ts new file mode 100644 index 000000000000..a6bf3d581116 --- /dev/null +++ b/galata/test/jupyterlab/cells.test.ts @@ -0,0 +1,34 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; +import * as path from 'path'; + +const fileName = 'simple_notebook.ipynb'; + +test.describe('Cells', () => { + test.beforeEach(async ({ page, request, tmpPath }) => { + const contents = galata.newContentsHelper(request); + await contents.uploadFile( + path.resolve(__dirname, `./notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + await contents.uploadFile( + path.resolve(__dirname, './notebooks/WidgetArch.png'), + `${tmpPath}/WidgetArch.png` + ); + + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + await page.notebook.activate(fileName); + }); + + test('should collapse a cell', async ({ page }) => { + await page.notebook.run(); + + await page.locator('.jp-Cell-inputCollapser').nth(2).click(); + + expect(await page.locator('.jp-Cell').nth(2).screenshot()).toMatchSnapshot( + 'collapsed-cell.png' + ); + }); +}); diff --git a/galata/test/jupyterlab/cells.test.ts-snapshots/collapsed-cell-jupyterlab-linux.png b/galata/test/jupyterlab/cells.test.ts-snapshots/collapsed-cell-jupyterlab-linux.png new file mode 100644 index 000000000000..5108feb78814 Binary files /dev/null and b/galata/test/jupyterlab/cells.test.ts-snapshots/collapsed-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/codemirror.test.ts b/galata/test/jupyterlab/codemirror.test.ts new file mode 100644 index 000000000000..ae38a7a25f8a --- /dev/null +++ b/galata/test/jupyterlab/codemirror.test.ts @@ -0,0 +1,43 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; + +const DEFAULT_NAME = 'untitled.txt'; + +const RULERS_CONTENT = `0123456789 + 0123456789 + 0123456789 + 0123456789 + 0123456789 + 0123456789 +0123456789 + 0123456789 + 0123456789 + 0123456789 + 0123456789 + 0123456789`; + +test.describe('CodeMirror extensions', () => { + test.use({ + mockSettings: { + ...galata.DEFAULT_SETTINGS, + '@jupyterlab/codemirror-extension:plugin': { + defaultConfig: { + rulers: [10, 20, 30, 40, 50, 60] + } + } + } + }); + + test('Should display rulers', async ({ page }) => { + await page.menu.clickMenuItem('File>New>Text File'); + + await page.getByRole('tab', { name: DEFAULT_NAME }).waitFor(); + + const editor = page.getByRole('region', { name: 'notebook content' }); + await editor.getByRole('textbox').fill(RULERS_CONTENT); + + expect(await editor.screenshot()).toMatchSnapshot('codemirror-rulers.png'); + }); +}); diff --git a/galata/test/jupyterlab/codemirror.test.ts-snapshots/codemirror-rulers-jupyterlab-linux.png b/galata/test/jupyterlab/codemirror.test.ts-snapshots/codemirror-rulers-jupyterlab-linux.png new file mode 100644 index 000000000000..e6a6bef5115b Binary files /dev/null and b/galata/test/jupyterlab/codemirror.test.ts-snapshots/codemirror-rulers-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts b/galata/test/jupyterlab/collapsible-headings.test.ts new file mode 100644 index 000000000000..d125a2ccc3aa --- /dev/null +++ b/galata/test/jupyterlab/collapsible-headings.test.ts @@ -0,0 +1,280 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { + expect, + galata, + IJupyterLabPageFixture, + test +} from '@jupyterlab/galata'; + +const fileName = 'notebook.ipynb'; + +// const menuPaths = ['File', 'Edit', 'View', 'Run', 'Kernel', 'Help']; + +async function populateNotebook(page: IJupyterLabPageFixture) { + await page.notebook.setCell(0, 'markdown', '# Heading 1'); + await page.notebook.addCell('code', '1+1'); + await page.notebook.addCell('code', '2+2'); +} + +test.describe('Collapsible Headings; showHCB', () => { + // create an empty notebook for each test + test.beforeEach(async ({ page }) => { + await page.notebook.createNew(fileName); + await populateNotebook(page); + await page.notebook.run(); + }); + + test('Show Collapser Unselected; showHCB', async ({ page }) => { + expect(await (await page.notebook.getCell(0)).screenshot()).toMatchSnapshot( + 'showHCB_heading_unselected.png' + ); + }); + + test('Show Collapser Selected; showHCB', async ({ page }) => { + await page.notebook.selectCells(0); + expect(await (await page.notebook.getCell(0)).screenshot()).toMatchSnapshot( + 'showHCB_heading_selected.png' + ); + }); + + test('Collapse Heading; showHCB', async ({ page }) => { + await page.notebook.selectCells(0); + await page.click('text=# Heading 1Heading 1Âļ >> button'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('showHCB_collapse_heading.png'); + }); + + test('Expand Heading via Collapser Button; showHCB', async ({ page }) => { + await page.notebook.selectCells(0); + await page.click('text=# Heading 1Heading 1Âļ >> button'); + await page.click('text=# Heading 1Heading 1Âļ >> button'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('showHCB_expand_heading_via_collapser.png'); + }); +}); + +test.describe('Collapsible Headings; no_showHCB', () => { + // create an empty notebook for each test + test.beforeEach(async ({ page }) => { + await page.notebook.createNew(fileName); + await populateNotebook(page); + await page.notebook.run(); + }); + // use non-standard showHiddenCellsButton=false + test.use({ + mockSettings: { + ...galata.DEFAULT_SETTINGS, + '@jupyterlab/notebook-extension:tracker': { + ...galata.DEFAULT_SETTINGS['@jupyterlab/notebook-extension:tracker'], + showHiddenCellsButton: false + } + } + }); + + test('Show Collapser Unselected; no_showHCB', async ({ page }) => { + expect(await (await page.notebook.getCell(0)).screenshot()).toMatchSnapshot( + 'no_showHCB_heading_unselected.png' + ); + }); + + test('Show Collapser Selected; no_showHCB', async ({ page }) => { + await page.notebook.selectCells(0); + expect(await (await page.notebook.getCell(0)).screenshot()).toMatchSnapshot( + 'no_showHCB_heading_selected.png' + ); + }); + + test('Collapse Heading; no_showHCB', async ({ page }) => { + await page.notebook.selectCells(0); + await page.click('text=# Heading 1Heading 1Âļ >> button'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('no_showHCB_collapse_heading.png'); + }); + + test('Expand Heading via Collapser Button; no_showHCB', async ({ page }) => { + await page.notebook.selectCells(0); + await page.click('text=# Heading 1Heading 1Âļ >> button'); + await page.click('text=# Heading 1Heading 1Âļ >> button'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('no_showHCB_expand_heading_via_collapser.png'); + }); +}); + +async function populateNotebook2(page: IJupyterLabPageFixture) { + await page.notebook.setCell(0, 'markdown', '# Heading 1'); + await page.notebook.addCell('code', '1+1'); + await page.notebook.addCell('markdown', '## Heading 1.1'); + await page.notebook.addCell('code', '2+2'); + await page.notebook.addCell('markdown', '# Heading 2'); + await page.notebook.addCell('code', '3+3'); + await page.notebook.addCell('code', '4+4'); +} + +test.describe('Collapsible Headings; keyboard navigation', () => { + // create an empty notebook for each test + test.beforeEach(async ({ page }) => { + await page.notebook.createNew(fileName); + await populateNotebook2(page); + await page.notebook.run(); + }); + + test('Jump to Previous Header', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('jump_previous_header.png'); + }); + + test('Collapse Previous Header', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('collapse_previous_header.png'); + }); + + test('Collapse Previous Headers', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('collapse_previous_headers.png'); + }); + + test('ReExpand Headers 01', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('a'); + await page.keyboard.press('ArrowRight'); + await page.keyboard.press('ArrowRight'); + await page.keyboard.press('ArrowRight'); + await page.keyboard.press('ArrowLeft'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('reexpand_headers_01.png'); + }); + + test('ReExpand Headers 02', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowDown'); + await page.keyboard.press('ArrowRight'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('reexpand_headers_02.png'); + }); + + test('ReExpand Headers 03', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowUp'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('reexpand_headers_03a.png'); + await page.keyboard.press('ArrowRight'); + await page.keyboard.press('ArrowRight'); + await page.keyboard.press('ArrowRight'); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('reexpand_headers_03b.png'); + }); + + test('Add Header Below 01', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('Shift+B'); + await page.waitForTimeout(200); + await page.keyboard.type('Heading 3'); + await page.keyboard.press('Shift+Enter'); + await page.notebook.selectCells(2); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('add_header_below_01.png'); + }); + + /** Check that header below adds header at end of present-level section. */ + test('Add Header Below 02', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('Shift+B'); + await page.waitForTimeout(200); + await page.keyboard.type('Heading 3'); + await page.keyboard.press('Shift+Enter'); + await page.notebook.selectCells(0); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('add_header_below_02.png'); + }); + + test('Add Header Below 03', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowUp'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('Shift+B'); + await page.waitForTimeout(200); + await page.keyboard.type('Heading 1.2'); + await page.keyboard.press('Shift+Enter'); + await page.notebook.selectCells(2); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('add_header_below_03.png'); + }); + + /** Checks also if the cursor is at the right position when adding heading */ + test('Add Header Above 01', async ({ page }) => { + await page.notebook.selectCells(6); + await page.keyboard.press('Shift+A'); + await page.waitForTimeout(200); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('add_header_above_01.png'); + }); + + /** Checks also if the cursor is at the right position when adding heading */ + test('Add Header Above 02', async ({ page }) => { + await page.notebook.selectCells(4); + await page.keyboard.press('Shift+A'); + await page.waitForTimeout(200); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('add_header_above_02.png'); + }); + + /** Checks also if the cursor is at the right position when adding heading */ + test('Add Header Above 03', async ({ page }) => { + await page.notebook.selectCells(3); + await page.keyboard.press('Shift+A'); + await page.waitForTimeout(200); + expect( + await (await page.notebook.getNotebookInPanel()).screenshot() + ).toMatchSnapshot('add_header_above_03.png'); + }); +}); diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-01-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-01-jupyterlab-linux.png new file mode 100644 index 000000000000..60868aca865f Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-01-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-02-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-02-jupyterlab-linux.png new file mode 100644 index 000000000000..6086f6eb9540 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-02-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-03-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-03-jupyterlab-linux.png new file mode 100644 index 000000000000..772533a12bec Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-above-03-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-01-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-01-jupyterlab-linux.png new file mode 100644 index 000000000000..b433ccb5d608 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-01-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-02-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-02-jupyterlab-linux.png new file mode 100644 index 000000000000..3922d28071a7 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-02-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-03-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-03-jupyterlab-linux.png new file mode 100644 index 000000000000..5715780899ad Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/add-header-below-03-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/collapse-previous-header-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/collapse-previous-header-jupyterlab-linux.png new file mode 100644 index 000000000000..dc93619b4258 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/collapse-previous-header-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/collapse-previous-headers-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/collapse-previous-headers-jupyterlab-linux.png new file mode 100644 index 000000000000..3199d832fa26 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/collapse-previous-headers-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/jump-previous-header-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/jump-previous-header-jupyterlab-linux.png new file mode 100644 index 000000000000..316211739667 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/jump-previous-header-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-collapse-heading-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-collapse-heading-jupyterlab-linux.png new file mode 100644 index 000000000000..89c8bb9f5152 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-collapse-heading-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-expand-heading-via-collapser-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-expand-heading-via-collapser-jupyterlab-linux.png new file mode 100644 index 000000000000..5dbc4aa79713 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-expand-heading-via-collapser-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-heading-selected-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-heading-selected-jupyterlab-linux.png new file mode 100644 index 000000000000..d2e14bb5334d Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-heading-selected-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-heading-unselected-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-heading-unselected-jupyterlab-linux.png new file mode 100644 index 000000000000..e72716f2baea Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/no-showHCB-heading-unselected-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-01-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-01-jupyterlab-linux.png new file mode 100644 index 000000000000..1f401d893d75 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-01-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-02-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-02-jupyterlab-linux.png new file mode 100644 index 000000000000..43edf4bc634e Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-02-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-03a-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-03a-jupyterlab-linux.png new file mode 100644 index 000000000000..3199d832fa26 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-03a-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-03b-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-03b-jupyterlab-linux.png new file mode 100644 index 000000000000..dc448a30c459 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/reexpand-headers-03b-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-collapse-heading-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-collapse-heading-jupyterlab-linux.png new file mode 100644 index 000000000000..125eebbfd53a Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-collapse-heading-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-expand-heading-via-collapser-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-expand-heading-via-collapser-jupyterlab-linux.png new file mode 100644 index 000000000000..5dbc4aa79713 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-expand-heading-via-collapser-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-heading-selected-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-heading-selected-jupyterlab-linux.png new file mode 100644 index 000000000000..d2e14bb5334d Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-heading-selected-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-heading-unselected-jupyterlab-linux.png b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-heading-unselected-jupyterlab-linux.png new file mode 100644 index 000000000000..4265f2c80d56 Binary files /dev/null and b/galata/test/jupyterlab/collapsible-headings.test.ts-snapshots/showHCB-heading-unselected-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/completer.test.ts b/galata/test/jupyterlab/completer.test.ts index 0cde24f7d01d..7dfa603ad0e5 100644 --- a/galata/test/jupyterlab/completer.test.ts +++ b/galata/test/jupyterlab/completer.test.ts @@ -1,7 +1,8 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { expect, test } from '@jupyterlab/galata'; +import { expect, galata, test } from '@jupyterlab/galata'; +import * as path from 'path'; const fileName = 'notebook.ipynb'; const COMPLETER_SELECTOR = '.jp-Completer'; @@ -25,12 +26,90 @@ test.describe('Completer', () => { // we need to wait until the completer gets bound to the cell after entering it await page.waitForTimeout(50); await page.keyboard.press('Tab'); + let completer = page.locator(COMPLETER_SELECTOR); + await completer.waitFor(); + await page.keyboard.press('Escape'); + await page.waitForTimeout(50); + await expect(completer).toBeHidden(); + await page.keyboard.press('Tab'); + completer = page.locator(COMPLETER_SELECTOR); + await completer.waitFor(); + const imageName = 'completer.png'; + expect(await completer.screenshot()).toMatchSnapshot(imageName); + }); - const completer = page.locator(COMPLETER_SELECTOR); + test('Show documentation panel', async ({ page, tmpPath }) => { + const scriptName = 'completer_panel.py'; + await page.contents.uploadFile( + path.resolve(__dirname, `./notebooks/${scriptName}`), + `${tmpPath}/${scriptName}` + ); + await galata.Mock.mockSettings(page, [], { + ...galata.DEFAULT_SETTINGS, + '@jupyterlab/completer-extension:manager': { + showDocumentationPanel: true + } + }); + await page.notebook.save(); + await page.goto(); + await page.notebook.openByPath(fileName); + + await page.notebook.setCell( + 0, + 'code', + 'from completer_panel import option_1, option_2' + ); + await page.notebook.runCell(0, true); + await page.notebook.addCell('code', 'option'); + await page.notebook.enterCellEditingMode(1); + + // we need to wait until the completer gets bound to the cell after entering it + await page.waitForTimeout(50); + await page.keyboard.press('Tab'); + let completer = page.locator(COMPLETER_SELECTOR); + await completer.waitFor(); + await page.keyboard.press('Escape'); + await page.waitForTimeout(50); + await expect(completer).toBeHidden(); + await page.keyboard.press('Tab'); + completer = page.locator(COMPLETER_SELECTOR); await completer.waitFor(); + await page.waitForSelector('.jp-Completer-loading-bar'); + await page.waitForSelector('.jp-Completer-loading-bar', { + state: 'detached' + }); + const imageName = 'completer-with-doc-panel.png'; + expect(await completer.screenshot()).toMatchSnapshot(imageName); + }); - const imageName = 'completer.png'; - // TODO: on first trigger types are not properly displayed, reference image will need updating + test('Token completions show up without running the cell when in the same cell', async ({ + page + }) => { + await page.notebook.setCell( + 0, + 'code', + 'option_1 = 1\n' + + 'option_2 = lambda x: x\n' + + 'option_3 = int\n' + + 'option' + ); + await page.notebook.enterCellEditingMode(0); + // move to the end of cell + await page.keyboard.press('PageDown'); + await page.keyboard.press('End'); + + // we need to wait until the completer gets bound to the cell after entering it + await page.waitForTimeout(50); + await page.keyboard.press('Tab'); + let completer = page.locator(COMPLETER_SELECTOR); + await completer.waitFor(); + await page.keyboard.press('Escape'); + await page.waitForTimeout(50); + await expect(completer).toBeHidden(); + await page.keyboard.press('Tab'); + completer = page.locator(COMPLETER_SELECTOR); + await completer.waitFor(); + const imageName = 'token-completer.png'; expect(await completer.screenshot()).toMatchSnapshot(imageName); }); @@ -49,10 +128,15 @@ test.describe('Completer', () => { await page.waitForTimeout(50); await page.keyboard.press('Tab'); - const completer = page.locator(COMPLETER_SELECTOR); + let completer = page.locator(COMPLETER_SELECTOR); await completer.waitFor(); - - await page.keyboard.type('g', { delay: 10 }); + await page.keyboard.press('Escape'); + await page.waitForTimeout(50); + await expect(completer).toBeHidden(); + await page.keyboard.press('Tab'); + completer = page.locator(COMPLETER_SELECTOR); + await completer.waitFor(); + await page.keyboard.type('g', { delay: 50 }); const imageName = 'completer-filter.png'; expect(await completer.screenshot()).toMatchSnapshot(imageName); @@ -65,7 +149,7 @@ test.describe('Completer', () => { await page.click('button:has-text("Select")'); - await page.waitForSelector('text=[ ]: ​ >> div[role="presentation"]'); + await page.waitForSelector('[aria-label="Code Cell Content"]'); await page.waitForSelector('text=| Idle'); await page.keyboard.type('import getopt\ngetopt.'); @@ -79,7 +163,6 @@ test.describe('Completer', () => { await completer.waitFor(); const imageName = 'completer-console.png'; - // TODO: on first trigger types are not properly displayed, reference image will need updating expect(await completer.screenshot()).toMatchSnapshot(imageName); }); diff --git a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-console-filter-jupyterlab-linux.png b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-console-filter-jupyterlab-linux.png index fa384308fadb..947ed7ad7faf 100644 Binary files a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-console-filter-jupyterlab-linux.png and b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-console-filter-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-console-jupyterlab-linux.png b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-console-jupyterlab-linux.png index e23198d28f13..840d72eceea9 100644 Binary files a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-console-jupyterlab-linux.png and b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-console-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-filter-jupyterlab-linux.png b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-filter-jupyterlab-linux.png index 37f0f8c16469..17ca32f2bb2c 100644 Binary files a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-filter-jupyterlab-linux.png and b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-filter-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-jupyterlab-linux.png b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-jupyterlab-linux.png index f43ac986eabd..b7c303c429de 100644 Binary files a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-jupyterlab-linux.png and b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/completer.test.ts-snapshots/completer-with-doc-panel-jupyterlab-linux.png b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-with-doc-panel-jupyterlab-linux.png new file mode 100644 index 000000000000..832ef417d1db Binary files /dev/null and b/galata/test/jupyterlab/completer.test.ts-snapshots/completer-with-doc-panel-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/completer.test.ts-snapshots/token-completer-jupyterlab-linux.png b/galata/test/jupyterlab/completer.test.ts-snapshots/token-completer-jupyterlab-linux.png new file mode 100644 index 000000000000..84a78caa7a38 Binary files /dev/null and b/galata/test/jupyterlab/completer.test.ts-snapshots/token-completer-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts b/galata/test/jupyterlab/contextmenu.test.ts index 9b2333b96c08..c8d2ce8ba3c3 100644 --- a/galata/test/jupyterlab/contextmenu.test.ts +++ b/galata/test/jupyterlab/contextmenu.test.ts @@ -15,8 +15,8 @@ test.use({ }); test.describe('Application Context Menu', () => { - test.beforeAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); + test.beforeAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); // Create some dummy content await contents.uploadFile( @@ -42,8 +42,8 @@ test.describe('Application Context Menu', () => { await page.filebrowser.openHomeDirectory(); }); - test.afterAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); + test.afterAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.deleteDirectory(tmpPath); }); @@ -110,7 +110,9 @@ test.describe('Application Context Menu', () => { expect(await page.menu.isAnyOpen()).toBe(true); await page.hover('text=Open With'); - await page.waitForSelector('li[role="menuitem"]:has-text("Editor")'); + await page.waitForSelector( + '.lm-Menu li[role="menuitem"]:has-text("Editor")' + ); const imageName = `file-openwith.png`; // Get the last menu -> will be submenu diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/file-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/file-jupyterlab-linux.png index 4d92b8926f33..7043e274882a 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/file-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/file-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/file-openwith-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/file-openwith-jupyterlab-linux.png index f77c59b7b406..964589a31158 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/file-openwith-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/file-openwith-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/fileeditor-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/fileeditor-jupyterlab-linux.png index 8849a3b16ed1..b7de06b2ec24 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/fileeditor-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/fileeditor-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/folder-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/folder-jupyterlab-linux.png index de85c6cfd98b..04de1b8aec0a 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/folder-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/folder-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/notebook-code-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/notebook-code-jupyterlab-linux.png index c290e9c9b4a9..ca8d5465c05a 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/notebook-code-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/notebook-code-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/notebook-md-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/notebook-md-jupyterlab-linux.png index 54c3e2d65a94..7d494a2f38b0 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/notebook-md-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/notebook-md-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/running-notebook-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/running-notebook-jupyterlab-linux.png index b2e516b6b371..79e01ea512fb 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/running-notebook-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/running-notebook-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/tab-launcher-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/tab-launcher-jupyterlab-linux.png index 341f99147b63..2b4bf02d59d9 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/tab-launcher-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/tab-launcher-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/tab-notebook-jupyterlab-linux.png b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/tab-notebook-jupyterlab-linux.png index da06f3337c11..084402dea7e1 100644 Binary files a/galata/test/jupyterlab/contextmenu.test.ts-snapshots/tab-notebook-jupyterlab-linux.png and b/galata/test/jupyterlab/contextmenu.test.ts-snapshots/tab-notebook-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/debugger.test.ts b/galata/test/jupyterlab/debugger.test.ts index 365d31841c9c..ee0713aa1b64 100644 --- a/galata/test/jupyterlab/debugger.test.ts +++ b/galata/test/jupyterlab/debugger.test.ts @@ -1,9 +1,24 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. +import { expect, IJupyterLabPageFixture, test } from '@jupyterlab/galata'; +import { PromiseDelegate } from '@lumino/coreutils'; +import * as path from 'path'; -import { expect, test } from '@jupyterlab/galata'; +async function openNotebook(page: IJupyterLabPageFixture, tmpPath, fileName) { + await page.contents.uploadFile( + path.resolve(__dirname, `./notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + await page.notebook.openByPath(`${tmpPath}/${fileName}`); +} test.describe('Debugger Tests', () => { + test.afterEach(async ({ page }) => { + await page.debugger.switchOff(); + await page.waitForTimeout(500); + await page.notebook.close(); + }); + test('Move Debugger to right', async ({ page }) => { await page.sidebar.moveTabToRight('jp-debugger-sidebar'); expect(await page.sidebar.getTabPosition('jp-debugger-sidebar')).toBe( @@ -15,4 +30,300 @@ test.describe('Debugger Tests', () => { await page.sidebar.openTab('jp-debugger-sidebar'); expect(await page.sidebar.isTabOpen('jp-debugger-sidebar')).toBeTruthy(); }); + + test('Start debug session', async ({ page, tmpPath }) => { + await openNotebook(page, tmpPath, 'code_notebook.ipynb'); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + + await page.notebook.waitForCellGutter(0); + await page.notebook.clickCellGutter(0, 2); + + await page.debugger.waitForBreakPoints(); + const breakpointsPanel = await page.debugger.getBreakPointsPanel(); + expect(await breakpointsPanel.innerText()).toMatch(/ipykernel/); + + const callStackPanel = await page.debugger.getCallStackPanel(); + expect(await callStackPanel.innerText()).toBe(''); + + // don't add await, run will be blocked by the breakpoint + void page.notebook.run().then(); + + await page.debugger.waitForCallStack(); + expect(await callStackPanel.innerText()).toMatch(/ipykernel/); + + await page.debugger.waitForVariables(); + const variablesPanel = await page.debugger.getVariablesPanel(); + expect(await variablesPanel.screenshot()).toMatchSnapshot( + 'start-debug-session-variables.png' + ); + + await page.debugger.waitForSources(); + const sourcesPanel = await page.debugger.getSourcePanel(); + expect(await sourcesPanel.screenshot()).toMatchSnapshot( + 'start-debug-session-sources.png' + ); + }); + + test('Rich variables inspector', async ({ page, tmpPath }) => { + await page.contents.uploadFile( + path.resolve(__dirname, './notebooks/WidgetArch.png'), + `${tmpPath}/WidgetArch.png` + ); + + const notebookName = 'image_notebook.ipynb'; + const globalVar = 'global_img'; + const localVar = 'local_img'; + + await openNotebook(page, tmpPath, notebookName); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + + await page.notebook.waitForCellGutter(0); + await page.notebook.clickCellGutter(0, 8); + await page.notebook.clickCellGutter(0, 11); + + // don't add await, run will be blocked by the breakpoint + void page.notebook.run().then(); + await page.debugger.waitForCallStack(); + + await page.debugger.waitForVariables(); + const variablesPanel = await page.debugger.getVariablesPanel(); + expect(await variablesPanel.screenshot()).toMatchSnapshot( + 'image-debug-session-global-variables.png' + ); + + await page.debugger.renderVariable(globalVar); + let richVariableTab = await page.activity.getPanel( + `${globalVar} - ${notebookName}` + ); + expect(await richVariableTab.screenshot()).toMatchSnapshot( + 'image-debug-session-global-rich-variable.png' + ); + + await page.activity.closePanel(`${globalVar} - ${notebookName}`); + + await page.locator('button[title="Continue (F9)"]').click(); + await expect(variablesPanel).not.toContain('ul'); + await page.debugger.waitForVariables(); + + await page.debugger.renderVariable(localVar); + richVariableTab = await page.activity.getPanel( + `${localVar} - ${notebookName}` + ); + expect(await richVariableTab.screenshot()).toMatchSnapshot( + 'image-debug-session-local-rich-variable.png' + ); + }); + + test('Start debug session (Script)', async ({ page, tmpPath }) => { + await openNotebook(page, tmpPath, 'code_script.py'); + + await page.click('div.jp-FileEditor', { + button: 'right' + }); + + const menu = await page.menu.getOpenMenu(); + await (await menu.$('[data-command="fileeditor:create-console"]')).click(); + + await page.waitForSelector('.jp-Dialog-body'); + const select = await page.$('.jp-Dialog-body >> select'); + const option = await select.$('option:has-text("ipykernel")'); + await select.selectOption(option); + await page.click('div.jp-Dialog-content >> button:has-text("Select")'); + + // activate the script tab + await page.click('.jp-FileEditor'); + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + await page.notebook.waitForCodeGutter(); + await page.notebook.clickCodeGutter(2); + + await page.debugger.waitForBreakPoints(); + const breakpointsPanel = await page.debugger.getBreakPointsPanel(); + expect(await breakpointsPanel.innerText()).toMatch(/ipykernel/); + + const callStackPanel = await page.debugger.getCallStackPanel(); + expect(await callStackPanel.innerText()).toBe(''); + + // don't add await, run will be blocked by the breakpoint + await page.menu.clickMenuItem('Run>Run All Code'); + + await page.debugger.waitForCallStack(); + expect(await callStackPanel.innerText()).toMatch(/ipykernel/); + + await page.debugger.waitForVariables(); + const variablesPanel = await page.debugger.getVariablesPanel(); + expect(await variablesPanel.screenshot()).toMatchSnapshot( + 'start-debug-session-script-variables.png' + ); + + await page.debugger.waitForSources(); + const sourcesPanel = await page.debugger.getSourcePanel(); + expect(await sourcesPanel.screenshot()).toMatchSnapshot( + 'start-debug-session-script-sources.png' + ); + }); +}); + +test.describe('Debugger Variables', () => { + test.use({ autoGoto: false }); + + const copyToGlobalsRequest = new PromiseDelegate(); + + test.beforeEach(async ({ page, tmpPath }) => { + // Listener to the websocket, to catch the 'copyToGlobals' request. + page.on('websocket', ws => { + ws.on('framesent', event => { + let message = event.payload; + if (Buffer.isBuffer(event.payload)) { + message = event.payload.toString('binary'); + } + if (message.includes('copyToGlobals')) { + copyToGlobalsRequest.resolve(); + } + }); + }); + + // Initialize the debugger. + await page.goto(`tree/${tmpPath}`); + await createNotebook(page); + + await page.debugger.switchOn(); + await page.waitForCondition(() => page.debugger.isOpen()); + + await setBreakpoint(page); + }); + + test('Copy to globals should work only for local variables', async ({ + page + }) => { + // Kernel supports copyToGlobals. + await page.evaluate(async () => { + const debuggerService = await window.galata.getPlugin( + '@jupyterlab/debugger-extension:service' + ); + debuggerService!.model.supportCopyToGlobals = true; + }); + + // Don't wait as it will be blocked. + void page.notebook.runCell(1); + + // Wait to be stopped on the breakpoint and the local variables to be displayed. + await page.debugger.waitForCallStack(); + + // Expect the copy entry to be in the menu. + await page.locator('select[aria-label="Scope"]').selectOption('Locals'); + await page.click('.jp-DebuggerVariables-body li span:text("local_var")', { + button: 'right' + }); + await expect( + page.locator('.lm-Menu-content li div:text("Copy Variable to Globals")') + ).toHaveCount(1); + + await expect( + page.locator('.lm-Menu-content li div:text("Copy Variable to Globals")') + ).toBeVisible(); + + // Request the copy of the local variable to globals scope. + await page.click( + '.lm-Menu-content li[data-command="debugger:copy-to-globals"]' + ); + + // Wait for the request to be sent. + await copyToGlobalsRequest.promise; + + // Expect the context menu for global variables to not have the 'copy' entry. + await page.locator('select[aria-label="Scope"]').selectOption('Globals'); + await page.click(`.jp-DebuggerVariables-body li span:text("global_var")`, { + button: 'right' + }); + await expect(page.locator('.lm-Menu-content')).toBeVisible(); + await expect( + page.locator('.lm-Menu-content li div:text("Copy Variable to Globals")') + ).toHaveCount(0); + }); + + test('Copy to globals not available from kernel', async ({ page }) => { + // Kernel doesn't support copyToGlobals. + await page.evaluate(async () => { + const debuggerService = await window.galata.getPlugin( + '@jupyterlab/debugger-extension:service' + ); + debuggerService!.model.supportCopyToGlobals = false; + }); + + // Don't wait as it will be blocked. + void page.notebook.runCell(1); + + // Wait to be stopped on the breakpoint and the local variables to be displayed. + await page.debugger.waitForCallStack(); + + await page.locator('select[aria-label="Scope"]').selectOption('Locals'); + + // Expect the menu entry not to be visible. + await page.click('.jp-DebuggerVariables-body li span:text("local_var")', { + button: 'right' + }); + await expect( + page.locator('.lm-Menu-content li div:text("Copy Variable to Globals")') + ).not.toBeVisible(); + + // Close the contextual menu + await page.keyboard.press('Escape'); + await expect( + page.locator('li.lm-Menu-item[data-command="debugger:copy-to-clipboard"]') + ).toHaveCount(0); + }); + + test('Copy to clipboard', async ({ page }) => { + // Don't wait as it will be blocked. + void page.notebook.runCell(1); + + // Wait to be stopped on the breakpoint and the local variables to be displayed. + await page.debugger.waitForCallStack(); + + // Copy value to clipboard + await page.locator('select[aria-label="Scope"]').selectOption('Locals'); + await page.click('.jp-DebuggerVariables-body li span:text("local_var")', { + button: 'right' + }); + await page.locator('.lm-Menu-itemLabel:text("Copy to Clipboard")').click(); + expect(await page.evaluate(() => navigator.clipboard.readText())).toBe('3'); + + // Copy to clipboard disabled for variables with empty value + await page.locator('select[aria-label="Scope"]').selectOption('Globals'); + await page + .locator('.jp-DebuggerVariables-body :text("special variables")') + .click({ button: 'right' }); + await expect( + page.locator('li.lm-Menu-item[data-command="debugger:copy-to-clipboard"]') + ).toHaveAttribute('aria-disabled', 'true'); + + // Close the contextual menu + await page.keyboard.press('Escape'); + await expect( + page.locator('li.lm-Menu-item[data-command="debugger:copy-to-clipboard"]') + ).toHaveCount(0); + }); }); + +async function createNotebook(page: IJupyterLabPageFixture) { + await page.notebook.createNew(); + + await page.waitForSelector('text=Python 3 (ipykernel) | Idle'); +} + +async function setBreakpoint(page: IJupyterLabPageFixture) { + await page.notebook.setCell( + 0, + 'code', + 'global_var = 1\ndef add(a, b):\nlocal_var = a + b\nreturn local_var' + ); + await page.notebook.run(); + await page.notebook.addCell('code', 'result = add(1, 2)\nprint(result)'); + + await page.notebook.clickCellGutter(0, 4); +} diff --git a/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-global-rich-variable-jupyterlab-linux.png b/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-global-rich-variable-jupyterlab-linux.png new file mode 100644 index 000000000000..f67a9f3e5438 Binary files /dev/null and b/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-global-rich-variable-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-global-variables-jupyterlab-linux.png b/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-global-variables-jupyterlab-linux.png new file mode 100644 index 000000000000..29be1389ce92 Binary files /dev/null and b/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-global-variables-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-local-rich-variable-jupyterlab-linux.png b/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-local-rich-variable-jupyterlab-linux.png new file mode 100644 index 000000000000..f67a9f3e5438 Binary files /dev/null and b/galata/test/jupyterlab/debugger.test.ts-snapshots/image-debug-session-local-rich-variable-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-script-sources-jupyterlab-linux.png b/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-script-sources-jupyterlab-linux.png new file mode 100644 index 000000000000..c0b68504a8d8 Binary files /dev/null and b/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-script-sources-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-script-variables-jupyterlab-linux.png b/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-script-variables-jupyterlab-linux.png new file mode 100644 index 000000000000..4c262ca6860d Binary files /dev/null and b/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-script-variables-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-sources-jupyterlab-linux.png b/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-sources-jupyterlab-linux.png new file mode 100644 index 000000000000..9e4d451741f2 Binary files /dev/null and b/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-sources-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-variables-jupyterlab-linux.png b/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-variables-jupyterlab-linux.png new file mode 100644 index 000000000000..4c262ca6860d Binary files /dev/null and b/galata/test/jupyterlab/debugger.test.ts-snapshots/start-debug-session-variables-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/general.test.ts-snapshots/dark-theme-jupyterlab-linux.png b/galata/test/jupyterlab/general.test.ts-snapshots/dark-theme-jupyterlab-linux.png index 1b705450a7c5..bc9e21bc000d 100644 Binary files a/galata/test/jupyterlab/general.test.ts-snapshots/dark-theme-jupyterlab-linux.png and b/galata/test/jupyterlab/general.test.ts-snapshots/dark-theme-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/general.test.ts-snapshots/launch-jupyterlab-linux.png b/galata/test/jupyterlab/general.test.ts-snapshots/launch-jupyterlab-linux.png index 8836cdcdfbbc..72c7f0191553 100644 Binary files a/galata/test/jupyterlab/general.test.ts-snapshots/launch-jupyterlab-linux.png and b/galata/test/jupyterlab/general.test.ts-snapshots/launch-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/general.test.ts-snapshots/simple-mode-jupyterlab-linux.png b/galata/test/jupyterlab/general.test.ts-snapshots/simple-mode-jupyterlab-linux.png index 52ca3f6a8b11..9c2ce8903d11 100644 Binary files a/galata/test/jupyterlab/general.test.ts-snapshots/simple-mode-jupyterlab-linux.png and b/galata/test/jupyterlab/general.test.ts-snapshots/simple-mode-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/help.test.ts b/galata/test/jupyterlab/help.test.ts index f41248dda436..75d12f315b86 100644 --- a/galata/test/jupyterlab/help.test.ts +++ b/galata/test/jupyterlab/help.test.ts @@ -28,5 +28,5 @@ test('Switch back and forth to reference page', async ({ page }) => { await expect( page.locator('.jp-MarkdownCell .jp-InputArea-editor') - ).toHaveText(`xxxxxxxxxx ${cellContent}`); + ).toHaveText(cellContent); }); diff --git a/galata/test/jupyterlab/html-viewer.test.ts b/galata/test/jupyterlab/html-viewer.test.ts new file mode 100644 index 000000000000..6d82f51a558e --- /dev/null +++ b/galata/test/jupyterlab/html-viewer.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { expect, test } from '@jupyterlab/galata'; + +test.describe('HTML Viewer', () => { + test.beforeEach(async ({ page }) => { + await page.menu.clickMenuItem('File>New>Text File'); + + await page.getByRole('main').getByRole('textbox').fill(` + +
    + GitHub + +`); + + await page.menu.clickMenuItem('File>Save Text'); + + await page.getByPlaceholder('File name').fill('test.html'); + await page.getByRole('button', { name: 'Rename' }).click(); + + await page.getByRole('listitem', { name: 'test.html' }).dblclick(); + }); + + test('should notify links are blocked for untrusted file', async ({ + page + }) => { + const frame = page.frame({ url: url => url.protocol == 'blob:' }); + await frame!.getByRole('link', { name: 'GitHub' }).hover(); + + const warningCount = await frame!.evaluate(() => { + let count = 0; + for (const link of document.querySelectorAll('a')) { + count += + window.getComputedStyle(link, '::after').content == + '"Action disabled as the file is not trusted."' + ? 1 + : 0; + } + return count; + }); + + expect(warningCount).toEqual(1); + }); + + test('should allow links for trusted file', async ({ page }) => { + await page.getByRole('button', { name: 'Trust HTML' }).click(); + const frame = page.frame({ url: url => url.protocol == 'blob:' }); + await frame!.getByRole('link', { name: 'GitHub' }).hover(); + + const warningCount = await frame!.evaluate(() => { + let count = 0; + for (const link of document.querySelectorAll('a')) { + count += + window.getComputedStyle(link, '::after').content == + '"Action disabled as the file is not trusted."' + ? 1 + : 0; + } + return count; + }); + + expect(warningCount).toEqual(0); + }); +}); diff --git a/galata/test/jupyterlab/kernel.test.ts b/galata/test/jupyterlab/kernel.test.ts new file mode 100644 index 000000000000..12d8bbf633ee --- /dev/null +++ b/galata/test/jupyterlab/kernel.test.ts @@ -0,0 +1,140 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, test } from '@jupyterlab/galata'; + +test.describe('Kernel', () => { + test.describe('Notebook', () => { + test('Should not ask kernel when creating notebook from launcher', async ({ + page + }) => { + await Promise.all([ + page + .getByRole('tabpanel', { name: 'Launcher' }) + .waitFor({ state: 'detached' }), + page.getByTitle('Python 3 (ipykernel)').nth(1).click() + ]); + + await expect.soft(page.locator('.jp-Dialog')).toHaveCount(0); + + await expect(page.getByTitle('Switch kernel')).toHaveText( + 'Python 3 (ipykernel)' + ); + }); + + test('Should remember kernel auto start for notebook', async ({ page }) => { + await page.menu.clickMenuItem('File>New>Notebook'); + + // Open a notebook without selecting a kernel + await page + .locator('.jp-Dialog') + .getByRole('button', { name: 'No Kernel' }) + .click(); + + await expect + .soft(page.getByTitle('Switch kernel')) + .toHaveText('No Kernel'); + + await Promise.all([ + page + .getByRole('tab', { name: 'Untitled.ipynb' }) + .waitFor({ state: 'detached' }), + page.menu.clickMenuItem('File>Close Tab') + ]); + + // Open the same notebook selecting and turning on auto start + await page.filebrowser.open('Untitled.ipynb'); + + await page + .locator('.jp-Dialog') + .getByText('Always start the preferred kernel') + .click(); + await page + .locator('.jp-Dialog') + .getByRole('button', { name: 'Select' }) + .click(); + + await expect + .soft(page.getByTitle('Switch kernel')) + .toHaveText('Python 3 (ipykernel)'); + + await page.menu.clickMenuItem('File>Close and Shut Down Notebook'); + + await Promise.all([ + page + .getByRole('tab', { name: 'Untitled.ipynb' }) + .waitFor({ state: 'detached' }), + page.locator('.jp-Dialog').getByRole('button', { name: 'Ok' }).click() + ]); + + // Open the same notebook and check it turns on the kernel + await page.filebrowser.open('Untitled.ipynb'); + + await expect(page.getByTitle('Switch kernel')).toHaveText( + 'Python 3 (ipykernel)' + ); + }); + + test('Should request kernel selection when executing a cell for notebook without kernel', async ({ + page + }) => { + await page.menu.clickMenuItem('File>New>Notebook'); + + // Open a notebook without selecting a kernel + await page + .locator('.jp-Dialog') + .getByRole('button', { name: 'No Kernel' }) + .click(); + + await expect + .soft(page.getByTitle('Switch kernel')) + .toHaveText('No Kernel'); + + // Request cell execution + await page.menu.clickMenuItem('Run>Run Selected Cell'); + + await page + .locator('.jp-Dialog') + .getByRole('button', { name: 'Select Kernel', exact: true }) + .click(); + + await expect(page.getByTitle('Switch kernel')).toHaveText( + 'Python 3 (ipykernel)' + ); + }); + }); + + test.describe('Console', () => { + test('Should not ask kernel when creating console from launcher', async ({ + page + }) => { + await Promise.all([ + page + .getByRole('tabpanel', { name: 'Launcher' }) + .waitFor({ state: 'detached' }), + page.getByTitle('Python 3 (ipykernel)').nth(2).click() + ]); + + await expect.soft(page.locator('.jp-Dialog')).toHaveCount(0); + + await expect(page.getByTitle('Change kernel for Console 1')).toHaveText( + 'Python 3 (ipykernel) | Idle' + ); + }); + + test('Should ask for kernel when creating console from menu', async ({ + page + }) => { + await page.menu.clickMenuItem('File>New>Console'); + + await page + .locator('.jp-Dialog') + .getByRole('button', { name: 'Select Kernel', exact: true }) + .click(); + + await expect(page.getByTitle('Change kernel for Console 1')).toHaveText( + 'Python 3 (ipykernel) | Idle' + ); + }); + }); +}); diff --git a/galata/test/jupyterlab/menus.test.ts b/galata/test/jupyterlab/menus.test.ts index 4863943c450e..f8ddc8188042 100644 --- a/galata/test/jupyterlab/menus.test.ts +++ b/galata/test/jupyterlab/menus.test.ts @@ -2,28 +2,29 @@ // Distributed under the terms of the Modified BSD License. import { expect, test } from '@jupyterlab/galata'; +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; const menuPaths = [ 'File', 'File>New', 'Edit', 'View', + 'View>Appearance', 'Run', 'Kernel', 'Tabs', 'Settings', 'Settings>Theme', 'Settings>Console Run Keystroke', - 'Settings>Text Editor Key Map', 'Settings>Text Editor Theme', 'Settings>Text Editor Indentation', 'Settings>Terminal Theme', 'Help' ]; -test.use({ autoGoto: false }); - test.describe('General Tests', () => { + test.use({ autoGoto: false }); + menuPaths.forEach(menuPath => { test(`Open menu item ${menuPath}`, async ({ page }) => { await page.goto(); @@ -41,8 +42,7 @@ test.describe('General Tests', () => { if (request.method() === 'GET') { return route.fulfill({ status: 200, - body: - '{"data": {"en": {"displayName": "English", "nativeName": "English"}}, "message": ""}' + body: '{"data": {"en": {"displayName": "English", "nativeName": "English"}}, "message": ""}' }); } else { return route.continue(); @@ -66,3 +66,113 @@ test.describe('General Tests', () => { expect(await page.menu.isAnyOpen()).toEqual(false); }); }); + +const EXPECTED_MISSING_COMMANDS_MAINMENU = ['hub:control-panel', 'hub:logout']; + +test('Main menu definition must target an valid command', async ({ page }) => { + const [menus, commands] = await page.evaluate(async () => { + const settings = await window.galata.getPlugin( + '@jupyterlab/apputils-extension:settings' + ); + const menus = await settings.get( + '@jupyterlab/mainmenu-extension:plugin', + 'menus' + ); + const commandIds = window.jupyterapp.commands.listCommands(); + + return Promise.resolve([ + menus.composite as ISettingRegistry.IMenu[], + commandIds + ]); + }); + + commands.push(...EXPECTED_MISSING_COMMANDS_MAINMENU); + + const missingCommands = menus.reduce((agg, current) => { + const items = + current.items?.reduce((agg, item) => { + const testedItem = reduceItem(item, commands); + if (testedItem !== null) { + agg.push(testedItem); + } + return agg; + }, []) ?? []; + if (items.length > 0) { + const r = {}; + r[current.label ?? 'unknown'] = items; + agg.push(r); + } + + return agg; + }, []); + + expect(missingCommands).toEqual([]); +}); + +test('Context menu definition must target an valid command', async ({ + page +}) => { + const [items, commands] = await page.evaluate(async () => { + const settings = await window.galata.getPlugin( + '@jupyterlab/apputils-extension:settings' + ); + const items = await settings.get( + '@jupyterlab/application-extension:context-menu', + 'contextMenu' + ); + const commandIds = window.jupyterapp.commands.listCommands(); + + return Promise.resolve([ + items.composite as ISettingRegistry.IMenuItem[], + commandIds + ]); + }); + + commands.push(...EXPECTED_MISSING_COMMANDS_MAINMENU); + + const missingCommands = items.reduce((agg, item) => { + const testedItem = reduceItem(item, commands); + if (testedItem !== null) { + agg.push(testedItem); + } + return agg; + }, []); + + expect(missingCommands).toEqual([]); +}); + +function reduceItem( + item: ISettingRegistry.IMenuItem, + commands: string[] +): + | ISettingRegistry.IMenuItem + | { [id: string]: ISettingRegistry.IMenuItem[] } + | null { + switch (item.type ?? 'command') { + case 'command': + if (!commands.includes(item.command)) { + return item; + } + break; + case 'submenu': { + const items = + item.submenu?.items?.reduce((agg, item) => { + const testedItem = reduceItem(item, commands); + if (testedItem !== null) { + agg.push(testedItem); + } + return agg; + }, []) ?? []; + if (items.length === 0) { + return null; + } else { + const r = {}; + r[item.submenu?.label ?? 'unknown'] = items; + return r; + } + } + default: + break; + } + return null; +} diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-edit-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-edit-jupyterlab-linux.png index f459111375ff..157f7194432e 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-edit-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-edit-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-file-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-file-jupyterlab-linux.png index 43b3e1e45816..091661e2e3d5 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-file-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-file-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-file-new-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-file-new-jupyterlab-linux.png index 74673f00b8ac..44dc7215ae34 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-file-new-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-file-new-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-help-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-help-jupyterlab-linux.png old mode 100755 new mode 100644 index 0555f5f9b154..e8e11aeaf384 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-help-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-help-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-kernel-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-kernel-jupyterlab-linux.png index 91ce1288420b..130c86c7adee 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-kernel-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-kernel-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-run-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-run-jupyterlab-linux.png index 98afe2980cc0..43ca401c8a62 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-run-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-run-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-console-run-keystroke-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-console-run-keystroke-jupyterlab-linux.png index e38fe32dd092..831536d6b07b 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-console-run-keystroke-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-console-run-keystroke-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-jupyterlab-linux.png index d2b8d6c77f5f..b193113aef52 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-language-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-language-jupyterlab-linux.png index 6e9e7b3ada63..308ca7dc9a17 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-language-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-language-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-terminal-theme-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-terminal-theme-jupyterlab-linux.png index dd160984ec0e..84d843d55ad0 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-terminal-theme-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-terminal-theme-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-indentation-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-indentation-jupyterlab-linux.png index 8509c2ebc68c..51683960d13b 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-indentation-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-indentation-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-theme-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-theme-jupyterlab-linux.png index 4ab9408ed1d4..8455b687a739 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-theme-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-theme-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-theme-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-theme-jupyterlab-linux.png index b8fb16ad004c..3b17f61ba0c0 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-theme-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-theme-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-tabs-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-tabs-jupyterlab-linux.png index 0c647ef2508c..ab68d2392430 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-tabs-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-tabs-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-view-appearance-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-view-appearance-jupyterlab-linux.png new file mode 100644 index 000000000000..354589f63ba4 Binary files /dev/null and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-view-appearance-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-view-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-view-jupyterlab-linux.png index 5e7c7d23099b..8144a1a5e70b 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-view-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-view-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menuedit-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menuedit-jupyterlab-linux.png index 19e1c411415c..34f813d026f4 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menuedit-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menuedit-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-extensionmanager-main-view-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-extensionmanager-main-view-jupyterlab-linux.png index b7adebf71912..4c9bf66f6e84 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-extensionmanager-main-view-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-extensionmanager-main-view-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-filebrowser-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-filebrowser-jupyterlab-linux.png index 2fc0abcbeff0..9c4b8fbb51ce 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-filebrowser-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-filebrowser-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-jp-property-inspector-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-jp-property-inspector-jupyterlab-linux.png index cbf9ad0913e8..bde708533908 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-jp-property-inspector-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-jp-property-inspector-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-jp-running-sessions-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-jp-running-sessions-jupyterlab-linux.png index 1a5480b202dd..36e470ba7d7b 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-jp-running-sessions-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-jp-running-sessions-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-table-of-contents-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-table-of-contents-jupyterlab-linux.png index 0d405f7789fd..4981056032d8 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-table-of-contents-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-sidebar-table-of-contents-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts b/galata/test/jupyterlab/metadataform.test.ts new file mode 100644 index 000000000000..cd78939010ae --- /dev/null +++ b/galata/test/jupyterlab/metadataform.test.ts @@ -0,0 +1,718 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import * as path from 'path'; +import { Page } from '@playwright/test'; +import { + expect, + galata, + IJupyterLabPageFixture, + test +} from '@jupyterlab/galata'; +import { ObservableJSON } from '@jupyterlab/observables'; + +const nbFile = 'code_notebook.ipynb'; +test.use({ + autoGoto: false, + tmpPath: 'metadataform-test', + waitForApplication: async ({ baseURL }, use, testInfo) => { + const simpleWait = async (page: Page): Promise => { + await page.waitForSelector('#jupyterlab-splash', { + state: 'detached' + }); + }; + void use(simpleWait); + } +}); + +test.beforeAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); + await contents.uploadFile( + path.resolve(__dirname, `./notebooks/${nbFile}`), + `${tmpPath}/${nbFile}` + ); +}); + +test.afterAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); + await contents.deleteDirectory(tmpPath); +}); + +/** + * Activate notebook tools side bar. + */ +async function activatePropertyInspector(page: IJupyterLabPageFixture) { + if ((await page.locator('.jp-NotebookTools').count()) > 0) { + if (await page.locator('.jp-NotebookTools').isVisible()) { + return; + } + } + + const widgetButton = page.locator( + ".lm-TabBar-tab[title='Property Inspector']" + ); + const buttonPosition = await widgetButton.boundingBox(); + + if (buttonPosition === null) + throw new Error( + 'Cannot get the position of the property inspector button.' + ); + + await page.mouse.click( + buttonPosition.x + buttonPosition.width / 2, + buttonPosition.y + buttonPosition.height / 2 + ); + + await expect(page.locator('.jp-NotebookTools')).toBeVisible(); +} + +/** + * Expand the form (open notebook tools if necessary) + */ +async function openForm( + page: IJupyterLabPageFixture, + label = 'Extension metadata' +) { + await activatePropertyInspector(page); + + const form = page.locator('.jp-NotebookTools .jp-Collapse', { + hasText: label + }); + if (form.locator('.jp-Collapse-contents.lm-mod-hidden')) { + await form.click(); + await expect( + form.locator('.jp-Collapse-contents.lm-mod-hidden') + ).toHaveCount(0); + } + return form; +} + +/** + * Return the formGroup DOM element after expanding the form. + */ +async function getFormGroup(page: IJupyterLabPageFixture) { + const form = await openForm(page); + return { + form: form, + formGroup: form.locator( + '.jp-Collapse-contents .jp-MetadataForm fieldset > .form-group' + ) + }; +} + +/* + * Get the cell metadata + */ +async function getCellMetadata( + page: IJupyterLabPageFixture, + cellNumber: number = 0 +): Promise { + return await page.evaluate(cellNum => { + let nb = window.jupyterapp.shell.currentWidget; + return nb.model.cells.get(cellNum).metadata; + }, cellNumber); +} + +/* + * Get the cell metadata + */ +async function getNotebookMetadata( + page: IJupyterLabPageFixture +): Promise { + return await page.evaluate(() => { + let nb = window.jupyterapp.shell.currentWidget; + return nb.model.metadata; + }); +} + +test.describe('Required metadata', () => { + test.use({ + mockSettings: { + '@jupyterlab/metadataform-extension:metadataforms': { + metadataforms: [ + { + id: 'Extension-metadata', + label: 'Extension metadata', + metadataSchema: { + type: 'object', + required: ['/basic-metadata'], + properties: { + '/basic-metadata': { + title: 'Basic metadata', + description: 'Basic metadata description', + type: 'string' + } + } + } + } + ] + } + } + }); + + test('should display the form', async ({ page, baseURL, tmpPath }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Activate the property inspector. + await activatePropertyInspector(page); + + // Retrieves the form from its header's text, it should be collapsed. + const form = page.locator('.jp-NotebookTools .jp-Collapse', { + hasText: 'Extension metadata' + }); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-collapsed-form.png' + ); + await expect( + form.locator('.jp-Collapse-contents.lm-mod-hidden') + ).toHaveCount(1); + + // Expand the form. + await form.click(); + await expect( + form.locator('.jp-Collapse-contents.lm-mod-hidden') + ).toHaveCount(0); + + // Get the formGroup (form content). + const formGroup = form.locator( + '.jp-Collapse-contents .jp-MetadataForm fieldset > .form-group' + ); + + // There should be only one field in formGroup, with correct title and description. + await expect(formGroup).toHaveCount(1); + await expect( + formGroup.locator('.jp-FormGroup-compactTitle > .jp-FormGroup-fieldLabel') + ).toHaveText('Basic metadata'); + await expect( + formGroup.locator( + '.jp-FormGroup-compactTitle > .jp-FormGroup-description' + ) + ).toHaveText('Basic metadata description'); + }); + + test('should fill metadata and display errors', async ({ + page, + baseURL, + tmpPath + }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM. + const { form, formGroup } = await getFormGroup(page); + + // Error should be displayed as required field is empty. + await expect(formGroup.locator('.validationErrors')).not.toBeEmpty(); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-required-missing.png' + ); + + // Relevant metadata should be empty. + let cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['basic-metadata']).toBeUndefined(); + + // Filling the form. + await formGroup.locator('input').fill('abc'); + + // Metadata should be filled, and error not displayed anymore. + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['basic-metadata']).toBe('abc'); + await expect(formGroup.locator('.validationErrors')).toBeEmpty(); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-required-filled.png' + ); + }); +}); + +test.describe('Nested metadata', () => { + test.use({ + mockSettings: { + '@jupyterlab/metadataform-extension:metadataforms': { + metadataforms: [ + { + id: 'Extension-metadata', + label: 'Extension metadata', + metadataSchema: { + type: 'object', + properties: { + '/level1/nested': { + title: 'Nested metadata 1', + type: 'integer' + }, + '/level1/level2/nested': { + title: 'Nested metadata 2', + type: 'integer' + } + } + } + } + ] + } + } + }); + + test('should fill nested metadata and remove the all tree if empty value', async ({ + page, + baseURL, + tmpPath + }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM. + const { formGroup } = await getFormGroup(page); + + // Metadata should be empty. + let cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['level1']).toBeUndefined(); + + // Replace the default value by 0, should write in metadata. + await formGroup.locator('input').last().fill('0'); + + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['level1']['level2']['nested']).toBe(0); + + // Empty the field, should remove the metadata tree. + await formGroup.locator('input').last().fill(''); + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['level1']).toBeUndefined(); + }); + + test('should remove only the empty metadata', async ({ + page, + baseURL, + tmpPath + }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM. + const { formGroup } = await getFormGroup(page); + + // Metadata should be empty. + let cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['level1']).toBeUndefined(); + + // Set the first level nested metadata. + await formGroup.locator('input').first().fill('1'); + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['level1']['nested']).toBe(1); + expect(cellMetadata['level1']['level2']).toBeUndefined(); + + // Set the second level nested metadata. + await formGroup.locator('input').last().fill('1'); + + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['level1']['level2']['nested']).toBe(1); + + // If the value of level2 is deleted, only the level2 metadata should be removed. + await formGroup.locator('input').last().fill(''); + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['level1']['nested']).toBe(1); + expect(cellMetadata['level1']['level2']).toBeUndefined(); + }); +}); + +test.describe('Default metadata without "showModified" flag', () => { + test.use({ + mockSettings: { + '@jupyterlab/metadataform-extension:metadataforms': { + metadataforms: [ + { + id: 'Extension-metadata', + label: 'Extension metadata', + metadataSchema: { + type: 'object', + properties: { + '/default-written': { + title: 'Default written', + type: 'integer', + default: 1 + }, + '/default-not-written': { + title: 'Default not written', + type: 'integer', + default: 1 + } + } + }, + metadataOptions: { + '/default-not-written': { + writeDefault: false + } + } + } + ] + } + } + }); + + test('should not fill metadata with "writeDefault" flag to false', async ({ + page, + baseURL, + tmpPath + }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM. + const { formGroup } = await getFormGroup(page); + + // Metadata should contains written default value. + let cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['default-written']).toBe(1); + + // Empty value should remove the metadata. + await formGroup.locator('input').first().fill(''); + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['default-written']).toBeUndefined(); + + // Fill the first one with default should be written in metadata. + await formGroup.locator('input').first().fill('1'); + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['default-written']).toBe(1); + + // Fill the second one with non default value should write metadata. + await formGroup.locator('input').last().fill('0'); + + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['default-not-written']).toBe(0); + + // Fill the second one with default value should remove the metadata. + await formGroup.locator('input').last().fill('1'); + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['default-not-written']).toBeUndefined(); + }); + + test('should not display the modified field', async ({ + page, + baseURL, + tmpPath + }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM. + const { formGroup } = await getFormGroup(page); + + // Metadata should contains written default value. + let cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['default-written']).toBe(1); + + // Fill the first one with default should be written in metadata. + await formGroup.locator('input').first().fill('2'); + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['default-written']).toBe(2); + + await expect(formGroup.locator('.jp-FormGroup-default')).toHaveCount(0); + }); +}); + +test.describe('Default metadata with "showModified" flag', () => { + test.use({ + mockSettings: { + '@jupyterlab/metadataform-extension:metadataforms': { + metadataforms: [ + { + id: 'Extension-metadata', + label: 'Extension metadata', + showModified: true, + metadataSchema: { + type: 'object', + properties: { + '/value-with-default': { + title: 'value with default', + type: 'integer', + default: 1 + } + } + } + } + ] + } + } + }); + + test('should display the modified field', async ({ + page, + baseURL, + tmpPath + }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM. + const { formGroup } = await getFormGroup(page); + + // Metadata should contains the default value. + let cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['value-with-default']).toBe(1); + + // Fill the field with non default value should display that value is different from default. + await formGroup.locator('input').first().fill('2'); + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['value-with-default']).toBe(2); + await expect(formGroup.locator('.jp-FormGroup-default')).toHaveCount(1); + await expect(formGroup.locator('.jp-FormGroup-default')).toContainText('1'); + }); +}); + +test.describe('Notebook level and cell type metadata', () => { + test.use({ + mockSettings: { + '@jupyterlab/metadataform-extension:metadataforms': { + metadataforms: [ + { + id: 'Extension-metadata', + label: 'Extension metadata', + metadataSchema: { + type: 'object', + properties: { + '/cell-metadata': { + title: 'Cell metadata', + type: 'string' + }, + '/nb-nested/nb-metadata': { + title: 'Notebook metadata', + type: 'string' + } + } + }, + metadataOptions: { + '/nb-nested/nb-metadata': { + metadataLevel: 'notebook' + }, + '/cell-metadata': { + cellTypes: ['code'] + } + } + } + ] + } + } + }); + + test('should manage cell and notebook metadata in the same form', async ({ + page, + baseURL, + tmpPath + }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM + const { form, formGroup } = await getFormGroup(page); + + // There should be 2 fields displayed. + await expect(formGroup).toHaveCount(2); + expect(await form.screenshot()).toMatchSnapshot('metadata-level.png'); + + // Metadata should be empty. + let cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['cell-metadata']).toBeUndefined(); + let nbMetadata = await getNotebookMetadata(page); + expect(nbMetadata['nb-nested']).toBeUndefined(); + + // Fill the first level nested metadata. + await formGroup.locator('input').first().fill('Cell input'); + await formGroup.locator('input').last().fill('Notebook input'); + + // Metadata should be filled at their correct level. + cellMetadata = await getCellMetadata(page, 0); + expect(cellMetadata['cell-metadata']).toBe('Cell input'); + expect(cellMetadata['nb-nested']).toBeUndefined(); + nbMetadata = await getNotebookMetadata(page); + expect(nbMetadata['nb-nested']['nb-metadata']).toBe('Notebook input'); + expect(nbMetadata['cell-metadata']).toBeUndefined(); + }); + + test('should not display field for non relevant cell type', async ({ + page, + baseURL, + tmpPath + }) => { + let form, formGroup; + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Create a Markdown cell and select it. + await page.notebook.addCell('markdown', 'Markdown cell'); + await page.notebook.selectCells((await page.notebook.getCellCount()) - 1); + ({ form, formGroup } = await getFormGroup(page)); + await expect(formGroup).toHaveCount(1); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-wrong-cell-type.png' + ); + + // Create a raw cell and select it. + await page.notebook.addCell('raw', 'Raw cell'); + await page.notebook.selectCells((await page.notebook.getCellCount()) - 1); + ({ form, formGroup } = await getFormGroup(page)); + await expect(formGroup).toHaveCount(1); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-wrong-cell-type.png' + ); + + // Select the code cell again to retrieve full form. + await page.notebook.selectCells(0); + ({ form, formGroup } = await getFormGroup(page)); + await expect(formGroup).toHaveCount(2); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-correct-cell-type.png' + ); + }); +}); + +test.describe('Conditional metadata', () => { + test.use({ + mockSettings: { + '@jupyterlab/metadataform-extension:metadataforms': { + metadataforms: [ + { + id: 'Extension-metadata', + label: 'Extension metadata', + metadataSchema: { + type: 'object', + properties: { + '/basic-metadata': { + title: 'Basic metadata', + type: 'string', + enum: ['not met', 'met'] + } + }, + allOf: [ + { + if: { + properties: { + '/basic-metadata': { + const: 'met' + } + } + }, + then: { + properties: { + '/conditional-field': { + title: 'conditional field', + type: 'string' + } + } + } + } + ] + } + } + ] + } + } + }); + + test('display conditional field', async ({ page, baseURL, tmpPath }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM + const { form, formGroup } = await getFormGroup(page); + + // There should be 1 field displayed as condition is not met. + await formGroup.locator('select').first().selectOption('not met'); + await expect(formGroup).toHaveCount(1); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-condition-not-met.png' + ); + + // Met the condition, then the second field should be displayed too. + await formGroup.locator('select').first().selectOption('met'); + await expect(formGroup).toHaveCount(2); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-condition-met.png' + ); + + // If the condition is not met, only one field should be displayed. + await formGroup.locator('select').first().selectOption('not met'); + await expect(formGroup).toHaveCount(1); + expect(await form.screenshot()).toMatchSnapshot( + 'metadata-condition-not-met.png' + ); + }); +}); + +test.describe('UISchema', () => { + test.use({ + mockSettings: { + '@jupyterlab/metadataform-extension:metadataforms': { + metadataforms: [ + { + id: 'Extension-metadata', + label: 'Extension metadata', + metadataSchema: { + type: 'object', + properties: { + '/metadata1': { + type: 'string' + }, + '/metadata2': { + title: 'Metadata 2', + type: 'integer' + } + } + }, + uiSchema: { + 'ui:order': ['/metadata2', '/metadata1'], + '/metadata1': { + 'ui:title': 'Metadata 1 title' + } + } + } + ] + } + } + }); + + test('should respect the order of the fields', async ({ + page, + baseURL, + tmpPath + }) => { + // Open the Notebook. + await page.goto(baseURL); + await page.notebook.openByPath(`${tmpPath}/${nbFile}`); + + // Open and get the form DOM. + const { form, formGroup } = await getFormGroup(page); + + // The order of the fields should be respected. + expect(await form.screenshot()).toMatchSnapshot('metadata-ui-schema.png'); + + await expect( + formGroup + .locator('.jp-FormGroup-compactTitle > .jp-FormGroup-fieldLabel') + .first() + ).toHaveText('Metadata 2'); + await expect(formGroup.locator('input').first()).toHaveAttribute( + 'type', + 'number' + ); + + // Should display the title and description from uiSchema. + await expect( + formGroup + .locator('.jp-FormGroup-compactTitle > .jp-FormGroup-fieldLabel') + .last() + ).toHaveText('Metadata 1 title'); + await expect(formGroup.locator('input').last()).toHaveAttribute( + 'type', + 'text' + ); + }); +}); diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-collapsed-form-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-collapsed-form-jupyterlab-linux.png new file mode 100644 index 000000000000..6462562521e4 Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-collapsed-form-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-condition-met-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-condition-met-jupyterlab-linux.png new file mode 100644 index 000000000000..aaf069fe9e9d Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-condition-met-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-condition-not-met-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-condition-not-met-jupyterlab-linux.png new file mode 100644 index 000000000000..f77791214ccc Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-condition-not-met-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-correct-cell-type-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-correct-cell-type-jupyterlab-linux.png new file mode 100644 index 000000000000..ccf92606e8b2 Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-correct-cell-type-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-level-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-level-jupyterlab-linux.png new file mode 100644 index 000000000000..8df600b7811c Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-level-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-required-filled-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-required-filled-jupyterlab-linux.png new file mode 100644 index 000000000000..511b4dcef22f Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-required-filled-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-required-missing-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-required-missing-jupyterlab-linux.png new file mode 100644 index 000000000000..9f76312a7d20 Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-required-missing-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-ui-schema-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-ui-schema-jupyterlab-linux.png new file mode 100644 index 000000000000..d433b32247d6 Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-ui-schema-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-wrong-cell-type-jupyterlab-linux.png b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-wrong-cell-type-jupyterlab-linux.png new file mode 100644 index 000000000000..74ba272f9da0 Binary files /dev/null and b/galata/test/jupyterlab/metadataform.test.ts-snapshots/metadata-wrong-cell-type-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-create.test.ts b/galata/test/jupyterlab/notebook-create.test.ts index 12e4eb25f5d4..e374d3060ff6 100644 --- a/galata/test/jupyterlab/notebook-create.test.ts +++ b/galata/test/jupyterlab/notebook-create.test.ts @@ -4,6 +4,7 @@ import { expect, IJupyterLabPageFixture, test } from '@jupyterlab/galata'; const fileName = 'notebook.ipynb'; +const TRUSTED_SELECTOR = 'svg[data-icon="ui-components:trusted"]'; const menuPaths = ['File', 'Edit', 'View', 'Run', 'Kernel', 'Help']; @@ -25,6 +26,7 @@ test.describe('Notebook Create', () => { await page.notebook.setCell(0, 'raw', 'Just a raw cell'); expect(await page.notebook.getCellCount()).toBe(1); expect(await page.notebook.getCellType(0)).toBe('raw'); + await expect(page.locator(TRUSTED_SELECTOR)).toHaveCount(1); }); test('Create a Markdown cell', async ({ page }) => { @@ -35,12 +37,14 @@ test.describe('Notebook Create', () => { await page.notebook.runCell(1, true); expect(await page.notebook.getCellCount()).toBe(2); expect(await page.notebook.getCellType(1)).toBe('markdown'); + await expect(page.locator(TRUSTED_SELECTOR)).toHaveCount(1); }); test('Create a Code cell', async ({ page }) => { await page.notebook.addCell('code', '2 ** 3'); expect(await page.notebook.getCellCount()).toBe(2); expect(await page.notebook.getCellType(1)).toBe('code'); + await expect(page.locator(TRUSTED_SELECTOR)).toHaveCount(1); }); test('Save Notebook', async ({ page }) => { @@ -72,6 +76,7 @@ test.describe('Notebook Create', () => { const imageName = 'run-cells.png'; expect((await page.notebook.getCellTextOutput(2))[0]).toBe('8'); + await expect(page.locator(TRUSTED_SELECTOR)).toHaveCount(1); const nbPanel = await page.notebook.getNotebookInPanel(); diff --git a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/dark-theme-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/dark-theme-jupyterlab-linux.png index 3dd4670b9588..5b7011f2d2c8 100644 Binary files a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/dark-theme-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/dark-theme-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-edit-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-edit-jupyterlab-linux.png index ac87753aa321..080a06cd7ef9 100644 Binary files a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-edit-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-edit-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-file-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-file-jupyterlab-linux.png index 45a3723420b9..6d11f93ba188 100644 Binary files a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-file-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-file-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-help-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-help-jupyterlab-linux.png index e4c974598405..cdf443fa8e50 100644 Binary files a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-help-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-help-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-kernel-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-kernel-jupyterlab-linux.png index 13cdfcddaa54..14639d10bbcd 100644 Binary files a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-kernel-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-kernel-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-run-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-run-jupyterlab-linux.png index 436f4ae972ef..40fd136f206d 100644 Binary files a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-run-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-run-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-view-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-view-jupyterlab-linux.png index e4355454f428..37ff8ad42569 100644 Binary files a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-view-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/opened-menu-view-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/run-cells-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/run-cells-jupyterlab-linux.png index 4cfd421b1b04..047f758bfe0d 100644 Binary files a/galata/test/jupyterlab/notebook-create.test.ts-snapshots/run-cells-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-create.test.ts-snapshots/run-cells-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts b/galata/test/jupyterlab/notebook-edit.test.ts index c8055d9ca337..59075eeaff04 100644 --- a/galata/test/jupyterlab/notebook-edit.test.ts +++ b/galata/test/jupyterlab/notebook-edit.test.ts @@ -55,9 +55,9 @@ test.describe('Notebook Edit', () => { let imageName = 'copy-paste-cell.png'; await page.notebook.selectCells(1); - await page.menu.clickMenuItem('Edit>Copy Cells'); + await page.menu.clickMenuItem('Edit>Copy Cell'); await page.notebook.selectCells(0); - await page.menu.clickMenuItem('Edit>Paste Cells Above'); + await page.menu.clickMenuItem('Edit>Paste Cell Above'); let nbPanel = await page.notebook.getNotebookInPanel(); expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); @@ -68,9 +68,9 @@ test.describe('Notebook Edit', () => { const imageName = 'cut-paste-cell.png'; await page.notebook.selectCells(0); - await page.menu.clickMenuItem('Edit>Cut Cells'); - await page.notebook.selectCells(2); - await page.menu.clickMenuItem('Edit>Paste Cells Below'); + await page.menu.clickMenuItem('Edit>Cut Cell'); + await page.notebook.selectCells(0); + await page.menu.clickMenuItem('Edit>Paste Cell Below'); const nbPanel = await page.notebook.getNotebookInPanel(); expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); @@ -81,9 +81,9 @@ test.describe('Notebook Edit', () => { const imageName = 'paste-replace-cell.png'; await page.notebook.selectCells(0); - await page.menu.clickMenuItem('Edit>Copy Cells'); + await page.menu.clickMenuItem('Edit>Copy Cell'); await page.notebook.selectCells(2); - await page.menu.clickMenuItem('Edit>Paste Cells and Replace'); + await page.menu.clickMenuItem('Edit>Paste Cell and Replace'); const nbPanel = await page.notebook.getNotebookInPanel(); expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); @@ -94,7 +94,7 @@ test.describe('Notebook Edit', () => { const imageName = 'delete-cell.png'; await page.notebook.selectCells(2); - await page.menu.clickMenuItem('Edit>Delete Cells'); + await page.menu.clickMenuItem('Edit>Delete Cell'); const nbPanel = await page.notebook.getNotebookInPanel(); expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); @@ -124,7 +124,7 @@ test.describe('Notebook Edit', () => { await populateNotebook(page); const imageName = 'move-cell-up.png'; await page.notebook.selectCells(1); - await page.menu.clickMenuItem('Edit>Move Cells Up'); + await page.menu.clickMenuItem('Edit>Move Cell Up'); const nbPanel = await page.notebook.getNotebookInPanel(); expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); @@ -134,7 +134,7 @@ test.describe('Notebook Edit', () => { await populateNotebook(page); const imageName = 'move-cell-down.png'; await page.notebook.selectCells(0); - await page.menu.clickMenuItem('Edit>Move Cells Down'); + await page.menu.clickMenuItem('Edit>Move Cell Down'); const nbPanel = await page.notebook.getNotebookInPanel(); expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); @@ -149,9 +149,10 @@ test.describe('Notebook Edit', () => { await page.keyboard.insertText('3 ** 2'); await page.keyboard.press('Home'); await page.menu.clickMenuItem('Edit>Split Cell'); + const nbPanel = await page.notebook.getNotebookInPanel(); - expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); + expect(await nbPanel!.screenshot()).toMatchSnapshot(imageName); }); test('Merge split cells', async ({ page }) => { diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/copy-paste-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/copy-paste-cell-jupyterlab-linux.png index 86b9acf6d6da..708fe7d2de11 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/copy-paste-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/copy-paste-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/cut-paste-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/cut-paste-cell-jupyterlab-linux.png index 4a27ff20c6c4..3b13be909742 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/cut-paste-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/cut-paste-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/delete-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/delete-cell-jupyterlab-linux.png index e5c3a011bfb2..8ab311123c46 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/delete-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/delete-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/deselect-all-cells-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/deselect-all-cells-jupyterlab-linux.png index cbdd49c0dc77..b60486a56c60 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/deselect-all-cells-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/deselect-all-cells-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/execute-again-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/execute-again-jupyterlab-linux.png index f190ea80cd72..66009e69edbe 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/execute-again-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/execute-again-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/merge-cells-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/merge-cells-jupyterlab-linux.png index b0cf0f0b4f31..4245eec2a280 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/merge-cells-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/merge-cells-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/move-cell-down-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/move-cell-down-jupyterlab-linux.png index 4a27ff20c6c4..3b13be909742 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/move-cell-down-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/move-cell-down-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/move-cell-up-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/move-cell-up-jupyterlab-linux.png index e9a1f05c8a38..5198ac51fd46 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/move-cell-up-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/move-cell-up-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/paste-replace-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/paste-replace-cell-jupyterlab-linux.png index f5fb550185c5..6540833df7d8 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/paste-replace-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/paste-replace-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/reedit-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/reedit-cell-jupyterlab-linux.png index f190ea80cd72..66009e69edbe 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/reedit-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/reedit-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/run-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/run-cell-jupyterlab-linux.png index 1da8d5d16103..6b3086686f18 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/run-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/run-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/select-all-cells-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/select-all-cells-jupyterlab-linux.png index 576966fca877..39e89ca7773e 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/select-all-cells-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/select-all-cells-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/split-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/split-cell-jupyterlab-linux.png index 1d7c0abc44bd..b51b88f47a5d 100644 Binary files a/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/split-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-edit.test.ts-snapshots/split-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/do-not-highlight-not-latex-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/do-not-highlight-not-latex-jupyterlab-linux.png index 2f9549e380fc..c66fdb644ebb 100644 Binary files a/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/do-not-highlight-not-latex-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/do-not-highlight-not-latex-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/do-not-highlight-standalone-dollar-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/do-not-highlight-standalone-dollar-jupyterlab-linux.png index ef0be004becd..3901d8bdf468 100644 Binary files a/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/do-not-highlight-standalone-dollar-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/do-not-highlight-standalone-dollar-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/highlight-latex-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/highlight-latex-jupyterlab-linux.png index a93cf68b74ed..7c808f7c5358 100644 Binary files a/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/highlight-latex-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-markdown.test.ts-snapshots/highlight-latex-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-max-outputs.test.ts b/galata/test/jupyterlab/notebook-max-outputs.test.ts index 715254c7870f..7790f14cce58 100644 --- a/galata/test/jupyterlab/notebook-max-outputs.test.ts +++ b/galata/test/jupyterlab/notebook-max-outputs.test.ts @@ -3,12 +3,14 @@ import { expect, galata, test } from '@jupyterlab/galata'; +const MAX_OUTPUTS = 5; + test.use({ mockSettings: { ...galata.DEFAULT_SETTINGS, '@jupyterlab/notebook-extension:tracker': { ...galata.DEFAULT_SETTINGS['@jupyterlab/notebook-extension:tracker'], - maxNumberOutputs: 5 + maxNumberOutputs: MAX_OUTPUTS } } }); @@ -16,10 +18,9 @@ test.use({ test('Limit cell outputs', async ({ page }) => { await page.notebook.createNew(); - await page.waitForSelector('text=| Idle'); - - await page.locator('div[role="main"] >> textarea') - .fill(`from IPython.display import display, Markdown + await page.locator( + '.jp-Cell-inputArea >> .cm-editor >> .cm-content[contenteditable="true"]' + ).type(`from IPython.display import display, Markdown for i in range(10): display(Markdown('_Markdown_ **text**')) @@ -27,23 +28,18 @@ for i in range(10): await page.notebook.run(); - await expect(page.locator('.jp-RenderedMarkdown')).toHaveCount(5); + await expect(page.locator('.jp-RenderedMarkdown')).toHaveCount(MAX_OUTPUTS); await expect(page.locator('.jp-TrimmedOutputs')).toHaveText( - ` - Output of this cell has been trimmed on the initial display. - Displaying the first 5 top outputs. - Click on this message to get the complete output. -` + 'Show more outputs' ); }); test("Don't limit cell outputs if input is requested", async ({ page }) => { await page.notebook.createNew(); - await page.waitForSelector('text=| Idle'); - - await page.locator('div[role="main"] >> textarea') - .fill(`from IPython.display import display, Markdown + await page.locator( + '.jp-Cell-inputArea >> .cm-editor >> .cm-content[contenteditable="true"]' + ).type(`from IPython.display import display, Markdown for i in range(10): display(Markdown('_Markdown_ **text**')) @@ -53,8 +49,9 @@ input('Your age:') await page.menu.clickMenuItem('Run>Run All Cells'); await page.waitForSelector('.jp-Stdin >> text=Your age:'); - - expect(await page.locator('.jp-RenderedMarkdown').count()).toBeGreaterThan(5); + expect(await page.locator('.jp-RenderedMarkdown').count()).toBeGreaterThan( + MAX_OUTPUTS + ); await page.keyboard.press('Enter'); }); @@ -62,10 +59,9 @@ input('Your age:') test('Display input value', async ({ page }) => { await page.notebook.createNew(); - await page.waitForSelector('text=| Idle'); - - await page.locator('div[role="main"] >> textarea') - .fill(`from IPython.display import display, Markdown + await page.locator( + '.jp-Cell-inputArea >> .cm-editor >> .cm-content[contenteditable="true"]' + ).type(`from IPython.display import display, Markdown for i in range(10): display(Markdown('_Markdown_ **text**')) @@ -82,7 +78,9 @@ for i in range(10): await page.keyboard.type('42'); await page.keyboard.press('Enter'); - expect(await page.locator('.jp-RenderedMarkdown').count()).toBeGreaterThan(5); + expect(await page.locator('.jp-RenderedMarkdown').count()).toBeGreaterThan( + MAX_OUTPUTS + ); await expect(page.locator('.jp-RenderedText').first()).toHaveText( 'Your age: 42' ); diff --git a/galata/test/jupyterlab/notebook-mobile.test.ts b/galata/test/jupyterlab/notebook-mobile.test.ts new file mode 100644 index 000000000000..a8bcd8e32972 --- /dev/null +++ b/galata/test/jupyterlab/notebook-mobile.test.ts @@ -0,0 +1,27 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, test } from '@jupyterlab/galata'; + +const fileName = 'notebook.ipynb'; + +test.use({ viewport: { width: 512, height: 768 } }); + +test.describe('Notebook Layout on Mobile', () => { + test.beforeEach(async ({ page }) => { + await page.notebook.createNew(fileName); + }); + + test('Execute code cell', async ({ page }) => { + await page.sidebar.close('left'); + // TODO: calling `setCell` just once leads to very flaky test + // See https://github.com/jupyterlab/jupyterlab/issues/15252 for more information + await page.notebook.setCell(0, 'code', 'print("hello")'); + await page.notebook.setCell(0, 'code', 'print("hello")'); + await page.notebook.addCell('code', '2 * 3'); + await page.notebook.runCellByCell(); + const nbPanel = await page.notebook.getNotebookInPanel(); + const imageName = 'mobile-layout.png'; + expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); + }); +}); diff --git a/galata/test/jupyterlab/notebook-mobile.test.ts-snapshots/mobile-layout-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-mobile.test.ts-snapshots/mobile-layout-jupyterlab-linux.png new file mode 100644 index 000000000000..1c94b10c405f Binary files /dev/null and b/galata/test/jupyterlab/notebook-mobile.test.ts-snapshots/mobile-layout-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-replace.test.ts b/galata/test/jupyterlab/notebook-replace.test.ts new file mode 100644 index 000000000000..14655b08f694 --- /dev/null +++ b/galata/test/jupyterlab/notebook-replace.test.ts @@ -0,0 +1,148 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { test } from '@jupyterlab/galata'; +import { expect } from '@playwright/test'; +import * as path from 'path'; + +const fileName = 'search.ipynb'; + +test.describe('Notebook Search and Replace', () => { + test.beforeEach(async ({ page, tmpPath }) => { + await page.contents.uploadFile( + path.resolve(__dirname, `./notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + await page.notebook.activate(fileName); + }); + + test.afterEach(async ({ page, tmpPath }) => { + await page.contents.deleteDirectory(tmpPath); + }); + + test('Replace in cell', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + await page.click('button[title="Toggle Replace"]'); + + await page.fill('[placeholder="Replace"]', 'egg'); + + await page.click('button:has-text("Replace")'); + + await page.waitForSelector('text=1/20'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot('replace-in-cell.png'); + }); + + test('Substitute groups of regular expressions', async ({ page }) => { + await page.keyboard.press('Control+f'); + + await page.click('button[title="Use Regular Expression"]'); + await page.fill('[placeholder="Find"]', 'text/(\\w+)'); + await page.waitForSelector('text=1/3'); + + await page.click('button[title="Toggle Replace"]'); + await page.fill('[placeholder="Replace"]', 'script/$1'); + const cell = await page.notebook.getCell(2); + await expect(page.locator('body')).not.toContainText('script/plain'); + + await page.click('button:has-text("Replace")'); + await page.waitForSelector('text=1/2'); + + await cell.waitForSelector('text=script/plain'); + await expect(page.locator('body')).toContainText('script/plain'); + }); + + test('Replace on markdown rendered cell', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + // Click next button + await page.click('button[title="Next Match"]', { + clickCount: 4 + }); + + await page.click('button[title="Toggle Replace"]'); + + await page.fill('[placeholder="Replace"]', 'egg'); + + await page.click('button:has-text("Replace")'); + + await page.waitForSelector('text=5/20'); + + const cell = await page.notebook.getCell(1); + + expect(await (await cell.$('.jp-Editor')).screenshot()).toMatchSnapshot( + 'replace-in-markdown-rendered-cell.png' + ); + }); + + test('Replace all', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + await page.click('button[title="Toggle Replace"]'); + + await page.fill('[placeholder="Replace"]', 'egg'); + + await page.click('button:has-text("Replace All")'); + + await page.waitForSelector('text=-/-'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot('replace-all.png'); + }); + + test('Replace step-by-step across cell boundaries', async ({ page }) => { + // Create a small test notebook + await page.notebook.createNew(); + await page.notebook.setCell(0, 'code', 'test\ntest'); + await page.notebook.addCell('code', 'test\ntest'); + + await page.keyboard.press('Control+f'); + await page.fill('[placeholder="Find"]', 'test'); + + await page.click('button[title="Toggle Replace"]'); + await page.fill('[placeholder="Replace"]', 'egg'); + + // TODO: Next Match press count should be one less + // (the -/4 state should not be necessary). + await page.waitForSelector('text=-/4'); + await page.click('button[title="Next Match"]', { + clickCount: 3 + }); + + await page.waitForSelector('text=1/4'); + await page.click('button:has-text("Replace")'); + + await page.waitForSelector('text=1/3'); + await page.click('button:has-text("Replace")'); + + // At this point we should be in the second cell + await page.waitForSelector('text=1/2'); + await page.click('button:has-text("Replace")'); + + await page.waitForSelector('text=1/1'); + + await page.click('button:has-text("Replace")'); + await page.waitForSelector('text=-/-'); + }); +}); diff --git a/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-all-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-all-jupyterlab-linux.png new file mode 100644 index 000000000000..573555930227 Binary files /dev/null and b/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-all-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-in-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-in-cell-jupyterlab-linux.png new file mode 100644 index 000000000000..b005de022cf9 Binary files /dev/null and b/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-in-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-in-markdown-rendered-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-in-markdown-rendered-cell-jupyterlab-linux.png new file mode 100644 index 000000000000..cf56fa5dbee1 Binary files /dev/null and b/galata/test/jupyterlab/notebook-replace.test.ts-snapshots/replace-in-markdown-rendered-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run-vega.test.ts b/galata/test/jupyterlab/notebook-run-vega.test.ts index b749aa136d8c..231b9efc9e35 100644 --- a/galata/test/jupyterlab/notebook-run-vega.test.ts +++ b/galata/test/jupyterlab/notebook-run-vega.test.ts @@ -1,59 +1,83 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { expect, galata, test } from '@jupyterlab/galata'; +import { + expect, + galata, + IJupyterLabPageFixture, + test +} from '@jupyterlab/galata'; import * as path from 'path'; const fileName = 'vega_notebook.ipynb'; -test.use({ tmpPath: 'notebook-run-vega-test' }); +const PNG_MIME_TYPE = 'image/png'; -test.describe.serial('Notebook Run Vega', () => { - test.beforeAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); +async function nbDiskContent( + page: IJupyterLabPageFixture, + nbPath: string +): Promise { + await page.notebook.save(); + // Use the `files` API as figure out the local path is though. + const response = await page.request.fetch(`/files/${nbPath}`); + if (!response.ok()) { + return ''; + } + const buffer = await response.body(); + return buffer.toString(); +} + +test.describe('Notebook Run Vega', () => { + test.beforeEach(async ({ page, request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.uploadFile( path.resolve(__dirname, `./notebooks/${fileName}`), `${tmpPath}/${fileName}` ); - }); - test.beforeEach(async ({ page, tmpPath }) => { await page.filebrowser.openDirectory(tmpPath); }); - test.afterAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); - await contents.deleteDirectory(tmpPath); - }); - test('Run notebook with Vega cell in default theme', async ({ page, tmpPath }) => { - await page.notebook.openByPath(`${tmpPath}/${fileName}`); + const nbPath = `${tmpPath}/${fileName}`; + await page.notebook.openByPath(nbPath); await page.notebook.activate(fileName); + expect(await nbDiskContent(page, nbPath)).not.toContain(PNG_MIME_TYPE); + const imageName = 'run-cells-vega.png'; await page.notebook.run(); - const graph = await page.waitForSelector('.vega-embed'); + await page.waitForSelector('.vega-embed'); + + const nbPanel = await page.notebook.getNotebookInPanel(); - expect(await graph.screenshot()).toMatchSnapshot(imageName); + expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); + expect(await nbDiskContent(page, nbPath)).toContain(PNG_MIME_TYPE); }); test('Run notebook with Vega cell in dark theme', async ({ page, tmpPath }) => { - await page.notebook.openByPath(`${tmpPath}/${fileName}`); + const nbPath = `${tmpPath}/${fileName}`; + await page.notebook.openByPath(nbPath); await page.notebook.activate(fileName); await page.theme.setDarkTheme(); + expect(await nbDiskContent(page, nbPath)).not.toContain(PNG_MIME_TYPE); + const imageName = 'run-cells-dark-vega.png'; await page.notebook.run(); - const graph = await page.waitForSelector('.vega-embed'); + await page.waitForSelector('.vega-embed'); + + const nbPanel = await page.notebook.getNotebookInPanel(); - expect(await graph.screenshot()).toMatchSnapshot(imageName); + expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); + expect(await nbDiskContent(page, nbPath)).toContain(PNG_MIME_TYPE); }); }); diff --git a/galata/test/jupyterlab/notebook-run-vega.test.ts-snapshots/run-cells-dark-vega-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run-vega.test.ts-snapshots/run-cells-dark-vega-jupyterlab-linux.png index d8fa42ca0b15..6a28fa9c1b00 100644 Binary files a/galata/test/jupyterlab/notebook-run-vega.test.ts-snapshots/run-cells-dark-vega-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-run-vega.test.ts-snapshots/run-cells-dark-vega-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run-vega.test.ts-snapshots/run-cells-vega-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run-vega.test.ts-snapshots/run-cells-vega-jupyterlab-linux.png index 6f5d43d0d258..f3bc34a3164d 100644 Binary files a/galata/test/jupyterlab/notebook-run-vega.test.ts-snapshots/run-cells-vega-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-run-vega.test.ts-snapshots/run-cells-vega-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run.test.ts b/galata/test/jupyterlab/notebook-run.test.ts index 52a16da0e340..fb44dc4fe2c8 100644 --- a/galata/test/jupyterlab/notebook-run.test.ts +++ b/galata/test/jupyterlab/notebook-run.test.ts @@ -9,8 +9,8 @@ const fileName = 'simple_notebook.ipynb'; test.use({ tmpPath: 'notebook-run-test' }); test.describe.serial('Notebook Run', () => { - test.beforeAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); + test.beforeAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.uploadFile( path.resolve(__dirname, `./notebooks/${fileName}`), `${tmpPath}/${fileName}` @@ -25,8 +25,8 @@ test.describe.serial('Notebook Run', () => { await page.filebrowser.openDirectory(tmpPath); }); - test.afterAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); + test.afterAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.deleteDirectory(tmpPath); }); @@ -59,7 +59,7 @@ test.describe.serial('Notebook Run', () => { numNBImages++; for (let c = 0; c < numNBImages; ++c) { - expect(captures[c]).toMatchSnapshot(getCaptureImageName(c)); + expect.soft(captures[c]).toMatchSnapshot(getCaptureImageName(c)); } }); diff --git a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-0-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-0-jupyterlab-linux.png index 1044d4e0ff96..ddfd8b30c538 100644 Binary files a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-0-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-0-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-1-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-1-jupyterlab-linux.png new file mode 100644 index 000000000000..93fd06f6c1ee Binary files /dev/null and b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-1-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-2-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-2-jupyterlab-linux.png new file mode 100644 index 000000000000..8719276372a4 Binary files /dev/null and b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-2-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-3-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-3-jupyterlab-linux.png new file mode 100644 index 000000000000..0b261a45c866 Binary files /dev/null and b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-3-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-4-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-4-jupyterlab-linux.png new file mode 100644 index 000000000000..64dd32c5f73f Binary files /dev/null and b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-4-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-5-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-5-jupyterlab-linux.png new file mode 100644 index 000000000000..90b4eeb1ab1a Binary files /dev/null and b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-5-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-6-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-6-jupyterlab-linux.png new file mode 100644 index 000000000000..9874d2120790 Binary files /dev/null and b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-6-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-7-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-7-jupyterlab-linux.png new file mode 100644 index 000000000000..9874d2120790 Binary files /dev/null and b/galata/test/jupyterlab/notebook-run.test.ts-snapshots/notebook-panel-7-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-scroll.test.ts b/galata/test/jupyterlab/notebook-scroll.test.ts new file mode 100644 index 000000000000..a02f4ef7817e --- /dev/null +++ b/galata/test/jupyterlab/notebook-scroll.test.ts @@ -0,0 +1,57 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; +import * as path from 'path'; + +const fileName = 'scroll.ipynb'; + +test.use({ + mockSettings: { + ...galata.DEFAULT_SETTINGS, + '@jupyterlab/notebook-extension:tracker': { + ...galata.DEFAULT_SETTINGS['@jupyterlab/notebook-extension:tracker'], + windowingMode: 'full' + } + } +}); + +test.describe('Notebook Scroll', () => { + test.beforeEach(async ({ page, tmpPath }) => { + await page.contents.uploadFile( + path.resolve(__dirname, `./notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + await page.notebook.activate(fileName); + }); + + test.afterEach(async ({ page, tmpPath }) => { + await page.contents.deleteDirectory(tmpPath); + }); + + const cellLinks = { + 'penultimate cell using heading, legacy format': 18, + 'penultimate cell using heading, explicit fragment': 18, + 'last cell using heading, legacy format': 19, + 'last cell using heading, explicit fragment': 19, + 'last cell using cell identifier': 19 + }; + for (const [link, cellIdx] of Object.entries(cellLinks)) { + test(`Scroll to ${link}`, async ({ page }) => { + const firstCell = await page.notebook.getCell(0); + await firstCell.scrollIntoViewIfNeeded(); + expect(await firstCell.boundingBox()).toBeTruthy(); + + await page.click(`a:has-text("${link}")`); + + await firstCell.waitForElementState('hidden'); + expect(await firstCell.boundingBox()).toBeFalsy(); + + const lastCell = await page.notebook.getCell(cellIdx); + await lastCell.waitForElementState('visible'); + expect(await lastCell.boundingBox()).toBeTruthy(); + }); + } +}); diff --git a/galata/test/jupyterlab/notebook-search.test.ts b/galata/test/jupyterlab/notebook-search.test.ts new file mode 100644 index 000000000000..585c8d07544b --- /dev/null +++ b/galata/test/jupyterlab/notebook-search.test.ts @@ -0,0 +1,537 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { test } from '@jupyterlab/galata'; +import { expect } from '@playwright/test'; +import * as path from 'path'; + +const fileName = 'search.ipynb'; + +function getSelectionRange(textarea: HTMLTextAreaElement) { + return { + start: textarea.selectionStart, + end: textarea.selectionEnd + }; +} + +test.describe('Notebook Search', () => { + test.beforeEach(async ({ page, tmpPath }) => { + await page.contents.uploadFile( + path.resolve(__dirname, `./notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + await page.notebook.activate(fileName); + }); + + test.afterEach(async ({ page, tmpPath }) => { + await page.contents.deleteDirectory(tmpPath); + }); + + test('Search', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot('search.png'); + }); + + test('Typing in search box', async ({ page }) => { + // Check against React being too eager with controling state of input box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', '14'); + await page.press('[placeholder="Find"]', 'ArrowLeft'); + await page.type('[placeholder="Find"]', '2'); + await page.type('[placeholder="Find"]', '3'); + + await expect(page.locator('[placeholder="Find"]')).toHaveValue('1234'); + }); + + test('RegExp parsing failure', async ({ page }) => { + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'test\\'); + + await page.click('button[title="Use Regular Expression"]'); + + await expect(page.locator('.jp-DocumentSearch-regex-error')).toBeVisible(); + + const overlay = page.locator('.jp-DocumentSearch-overlay'); + + expect(await overlay.screenshot()).toMatchSnapshot( + 'regexp-parsing-failure.png' + ); + }); + + test('Multi-line search', async ({ page }) => { + await page.keyboard.press('Control+f'); + + await page.fill( + '[placeholder="Find"]', + 'one notebook withr\n\n\nThis is a multi' + ); + + await page.waitForSelector('text=1/1'); + + // Show replace buttons to check for visual regressions + await page.click('button[title="Toggle Replace"]'); + await page.fill('[placeholder="Replace"]', 'line1\nline2'); + + const overlay = page.locator('.jp-DocumentSearch-overlay'); + expect(await overlay.screenshot()).toMatchSnapshot('multi-line-search.png'); + }); + + test('Populate search box with selected text', async ({ page }) => { + // Enter first cell + await page.notebook.enterCellEditingMode(0); + + // Go to first line + await page.keyboard.press('PageUp'); + // Select first line + await page.keyboard.press('Shift+End'); + // Open search box + await page.keyboard.press('Control+f'); + + // Expect it to be populated with the first line + const inputWithFirstLine = page.locator( + '[placeholder="Find"] >> text="Test with one notebook withr"' + ); + await expect(inputWithFirstLine).toBeVisible(); + await expect(inputWithFirstLine).toBeFocused(); + // Expect the newly set text to be selected + expect(await inputWithFirstLine.evaluate(getSelectionRange)).toStrictEqual({ + start: 0, + end: 28 + }); + + // Expect the first match to be highlighted + await page.waitForSelector('text=1/2'); + + // Enter first cell again + await page.notebook.enterCellEditingMode(0); + // Go to last line + await page.keyboard.press('PageDown'); + // Select last line + await page.keyboard.press('Shift+Home'); + // Update search box + await page.keyboard.press('Control+f'); + + // Expect it to be populated with the last line + const inputWithLastLine = page.locator( + '[placeholder="Find"] >> text="This is a multi line with hits with"' + ); + await expect(inputWithLastLine).toBeVisible(); + await expect(inputWithLastLine).toBeFocused(); + // Expect the newly set text to be selected + expect(await inputWithLastLine.evaluate(getSelectionRange)).toStrictEqual({ + start: 0, + end: 35 + }); + + await expect(page.locator('.jp-DocumentSearch-overlay')).toBeVisible(); + }); + + test('Restore previous search query if there is no selection', async ({ + page + }) => { + const inputWithTestLocator = page.locator( + '[placeholder="Find"] >> text="test"' + ); + const overlayLocator = page.locator('.jp-DocumentSearch-overlay'); + + // Search for "test" + await page.keyboard.press('Control+f'); + await page.fill('[placeholder="Find"]', 'test'); + await page.waitForSelector('text=1/2'); + + // Close search box + await page.keyboard.press('Escape'); + await expect(overlayLocator).toBeHidden(); + + // Open search box again + await page.keyboard.press('Control+f'); + await expect(overlayLocator).toBeVisible(); + // Expect the text to be set in the input field + await expect(inputWithTestLocator).toBeVisible(); + // Expect the search to be active again + await page.waitForSelector('text=1/2'); + }); + + test('Close with Escape', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + await expect(page.locator('.jp-DocumentSearch-overlay')).toBeVisible(); + + // Close search box + await page.keyboard.press('Escape'); + await expect(page.locator('.jp-DocumentSearch-overlay')).toBeHidden(); + }); + + test('Close with Escape from Notebook', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + await expect(page.locator('.jp-DocumentSearch-overlay')).toBeVisible(); + + // Enter first cell + await page.notebook.enterCellEditingMode(0); + + // First escape should NOT close the search box (but leave the editing mode) + await page.keyboard.press('Escape'); + await page.waitForTimeout(250); + expect(await page.notebook.isCellInEditingMode(0)).toBeFalsy(); + expect(await page.isVisible('.jp-DocumentSearch-overlay')).toBeTruthy(); + + // Second escape should close the search box (even if it is not focused) + await page.keyboard.press('Escape'); + await expect(page.locator('.jp-DocumentSearch-overlay')).toBeHidden(); + }); + + test('Search within outputs', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.click('button[title="Show Search Filters"]'); + + await page.click('text=Search Cell Outputs'); + + // If the notebook is not fully loaded yet a confirmation dialog will show up + if (await page.locator('.jp-Dialog').isVisible()) { + await page.click('.jp-Dialog .jp-mod-accept'); + } + + await page.waitForSelector('text=1/29'); + + const cell = await page.notebook.getCell(5); + await cell.scrollIntoViewIfNeeded(); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot( + 'search-within-outputs.png' + ); + }); + + test('Search in a single selected cell', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.click('button[title="Show Search Filters"]'); + + await page.click('text=Search in 1 Selected Cell'); + + await page.waitForSelector('text=1/4'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + expect(await nbPanel.screenshot()).toMatchSnapshot( + 'search-in-selected-cells.png' + ); + }); + + test('Search in multiple selected cells', async ({ page }) => { + await page.keyboard.press('Control+f'); + await page.fill('[placeholder="Find"]', 'with'); + await page.click('button[title="Show Search Filters"]'); + await page.click('text=Search in 1 Selected Cell'); + + // Bring focus to first cell without switching away from command mode + let cell = await page.notebook.getCell(0); + await (await cell.$('.jp-InputPrompt')).click(); + + // Select two cells below + await page.keyboard.press('Shift+ArrowDown'); + await page.keyboard.press('Shift+ArrowDown'); + + // Expect the filter text to be updated + await page.waitForSelector('text=Search in 3 Selected Cells'); + + // Reset selection, switch to third cell, preserving command mode + cell = await page.notebook.getCell(2); + await (await cell.$('.jp-InputPrompt')).click(); + + await page.waitForSelector('text=Search in 1 Selected Cell'); + + // Select cell above + await page.keyboard.press('Shift+ArrowUp'); + + // Expect updated text + await page.waitForSelector('text=Search in 2 Selected Cells'); + + // Expect 15 matches; this is 6/15, not 1/15 because current match is set + // in second cell and when selection is extended, it does not move; keeping + // the current match when extending the selection is desired as user may use + // it as a reference, especially when it was set as closest to the cursor. + await page.waitForSelector('text=6/15'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + expect(await nbPanel.screenshot()).toMatchSnapshot( + 'search-in-two-selected-cells.png' + ); + }); + + test('Search in multiple selected cells from edit mode', async ({ page }) => { + // This is testing focus handling when extending the selection after + // switching focus away from cell editor, which needs to protect against + // race conditions and CodeMirror6 focus issues when highlights get added. + await page.keyboard.press('Control+f'); + await page.fill('[placeholder="Find"]', 'with'); + await page.click('button[title="Show Search Filters"]'); + await page.click('text=Search in 1 Selected Cell'); + await page.waitForSelector('text=1/4'); + + // Bring focus to first cell without switching to edit mode + let cell = await page.notebook.getCell(0); + await (await cell.$('.jp-Editor')).click(); + + // Switch back to command mode + await page.keyboard.press('Escape'); + + // Select two cells below + await page.keyboard.press('Shift+ArrowDown'); + await page.keyboard.press('Shift+ArrowDown'); + + // Expect the filter text to be updated + await page.waitForSelector('text=Search in 3 Selected Cells'); + + // Expect 19 matches + await page.waitForSelector('text=1/19'); + }); + + test('Search in selected text', async ({ page }) => { + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'text/'); + await page.waitForSelector('text=1/3'); + + // Activate third cell + const cell = await page.notebook.getCell(2); + const editor = await cell.$('.jp-Editor'); + await editor.click(); + + // Select 7 lines + await page.keyboard.press('Control+Home'); + for (let i = 0; i < 6; i++) { + await page.keyboard.press('Shift+ArrowDown'); + } + + // Switch to selection search mode + await page.click('button[title="Show Search Filters"]'); + await page.click('text=Search in 7 Selected Lines'); + + await page.waitForSelector('text=1/2'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot( + 'search-in-selected-text.png' + ); + }); + + test('Highlights are visible when text is selected', async ({ page }) => { + await page.keyboard.press('Control+f'); + await page.fill('[placeholder="Find"]', 'with'); + await page.waitForSelector('text=1/21'); + + const cell = await page.notebook.getCell(0); + const editor = await cell.$('.jp-Editor'); + await editor.click(); + + // Select text (to see if the highlights will still be visible) + await page.keyboard.press('Control+A'); + + expect(await (await cell.$('.jp-Editor')).screenshot()).toMatchSnapshot( + 'highlight-visible-under-selection.png' + ); + }); + + test('Highlight next hit same editor', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + // Click next button + await page.click('button[title="Next Match"]'); + + const cell = await page.notebook.getCell(0); + + expect(await (await cell.$('.jp-Editor')).screenshot()).toMatchSnapshot( + 'highlight-next-in-editor.png' + ); + }); + + test('Highlight next hit in the next cell', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + // Click next button + await page.click('button[title="Next Match"]', { + clickCount: 4 + }); + + const cell = await page.notebook.getCell(1); + + expect(await cell.screenshot()).toMatchSnapshot('highlight-next-cell.png'); + }); + + test('Highlight previous hit', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + // Click previous button + await page.click('button[title="Previous Match"]'); + // Should cycle back + await page.waitForSelector('text=21/21'); + + // Click previous button twice + await page.click('button[title="Previous Match"]'); + await page.click('button[title="Previous Match"]'); + // Should move up by two + await page.waitForSelector('text=19/21'); + + const hit = await page.notebook.getCell(2); + expect(await hit.screenshot()).toMatchSnapshot( + 'highlight-previous-element.png' + ); + }); + + test('Search from cursor', async ({ page }) => { + const cell = await page.notebook.getCell(5); + await cell.click(); + await page.keyboard.press('Escape'); + await cell.scrollIntoViewIfNeeded(); + + // Open search box + await page.keyboard.press('Control+f'); + await page.fill('[placeholder="Find"]', 'with'); + await page.waitForSelector('text=20/21'); + + // Click previous button + await page.click('button[title="Previous Match"]'); + await page.waitForSelector('text=19/21'); + }); + + test('Highlight on markdown rendered state change', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + // Click next button + await page.click('button[title="Next Match"]', { + clickCount: 4 + }); + + const cell = await page.notebook.getCell(1); + + await cell.dblclick(); + + expect(await (await cell.$('.jp-Editor')).screenshot()).toMatchSnapshot( + 'highlight-markdown-switch-state.png' + ); + }); + + test('Search on typing', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + // Wait until search has settled before entering a cell for edition + // as this can lead to selection of active result near that cell + // (rather than at the beginning of the notebook) + await page.waitForSelector('text=1/21'); + + await page.notebook.setCell(5, 'code', 'with'); + + const cell = await page.notebook.getCell(5); + expect(await cell.screenshot()).toMatchSnapshot('search-typing.png'); + }); + + test('Search new outputs', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.click('button[title="Show Search Filters"]'); + + await page.click('text=Search Cell Outputs'); + + await page.waitForSelector('text=1/29'); + + const cell = await page.notebook.getCell(5); + + await cell.click(); + + await page.notebook.runCell(5); + expect(await cell.screenshot()).toMatchSnapshot('search-new-outputs.png'); + }); + + test('Search on new cell', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + const cell = await page.notebook.getCell(5); + await cell.click(); + await page.notebook.clickToolbarItem('insert'); + await page.notebook.setCell(6, 'code', 'with'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot( + 'search-on-new-cell.png' + ); + }); + + test('Search on deleted cell', async ({ page }) => { + // Open search box + await page.keyboard.press('Control+f'); + + await page.fill('[placeholder="Find"]', 'with'); + + await page.waitForSelector('text=1/21'); + + const cell = await page.notebook.getCell(5); + await cell.click(); + await page.keyboard.press('Escape'); + await cell.scrollIntoViewIfNeeded(); + + await page.keyboard.press('d'); + await page.keyboard.press('d'); + + await page.waitForSelector('text=1/19'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot( + 'search-on-deleted-cell.png' + ); + }); +}); diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-markdown-switch-state-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-markdown-switch-state-jupyterlab-linux.png new file mode 100644 index 000000000000..135c98ac27d6 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-markdown-switch-state-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-next-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-next-cell-jupyterlab-linux.png new file mode 100644 index 000000000000..5f217070e979 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-next-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-next-in-editor-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-next-in-editor-jupyterlab-linux.png new file mode 100644 index 000000000000..2934725a4561 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-next-in-editor-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-previous-element-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-previous-element-jupyterlab-linux.png new file mode 100644 index 000000000000..b7cd99643070 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-previous-element-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-visible-under-selection-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-visible-under-selection-jupyterlab-linux.png new file mode 100644 index 000000000000..e638fec7d18d Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/highlight-visible-under-selection-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/multi-line-search-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/multi-line-search-jupyterlab-linux.png new file mode 100644 index 000000000000..30d9e9f3fbec Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/multi-line-search-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/regexp-parsing-failure-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/regexp-parsing-failure-jupyterlab-linux.png new file mode 100644 index 000000000000..f32da74eff95 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/regexp-parsing-failure-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-selected-cells-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-selected-cells-jupyterlab-linux.png new file mode 100644 index 000000000000..c4f9e2513506 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-selected-cells-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-selected-text-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-selected-text-jupyterlab-linux.png new file mode 100644 index 000000000000..379c2cee5f88 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-selected-text-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-two-selected-cells-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-two-selected-cells-jupyterlab-linux.png new file mode 100644 index 000000000000..5d0d182731cf Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-in-two-selected-cells-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-jupyterlab-linux.png new file mode 100644 index 000000000000..1dc949edbaf2 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-new-outputs-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-new-outputs-jupyterlab-linux.png new file mode 100644 index 000000000000..57819f74e41c Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-new-outputs-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-on-deleted-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-on-deleted-cell-jupyterlab-linux.png new file mode 100644 index 000000000000..f3a8acbdee19 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-on-deleted-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-on-new-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-on-new-cell-jupyterlab-linux.png new file mode 100644 index 000000000000..96324586de1a Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-on-new-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-typing-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-typing-jupyterlab-linux.png new file mode 100644 index 000000000000..844c596ee1ce Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-typing-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-within-outputs-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-within-outputs-jupyterlab-linux.png new file mode 100644 index 000000000000..ecb9f58c3e22 Binary files /dev/null and b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-within-outputs-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts b/galata/test/jupyterlab/notebook-toolbar.test.ts index 016a5c9ab125..78a574d38157 100644 --- a/galata/test/jupyterlab/notebook-toolbar.test.ts +++ b/galata/test/jupyterlab/notebook-toolbar.test.ts @@ -57,7 +57,7 @@ test.describe('Notebook Toolbar', () => { await page.notebook.clickToolbarItem('cut'); const imageName = 'paste-cell.png'; - await page.notebook.selectCells(2); + await page.notebook.selectCells(1); await page.notebook.clickToolbarItem('paste'); const nbPanel = await page.notebook.getNotebookInPanel(); @@ -79,7 +79,6 @@ test.describe('Notebook Toolbar', () => { await page.notebook.clickToolbarItem('run'); await page.waitForSelector('text=8'); - // await page.notebook.waitForRun(); const nbPanel = await page.notebook.getNotebookInPanel(); @@ -130,7 +129,9 @@ test('Toolbar items act on owner widget', async ({ page }) => { expect(classlist.split(' ')).not.toContain('jp-mod-current'); // When clicking on toolbar item of the first file - await (await panel1.$('button[title="Insert a cell below (B)"]')).click(); + await ( + await panel1.$('button[data-command="notebook:insert-cell-below"]') + ).click(); // Then the first file is activated and the action is performed const classlistEnd = await tab1.getAttribute('class'); diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/change-to-markdown-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/change-to-markdown-jupyterlab-linux.png index 90a2c4245215..1802e0757171 100644 Binary files a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/change-to-markdown-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/change-to-markdown-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/copy-paste-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/copy-paste-cell-jupyterlab-linux.png index 597c0b00a7ed..6573efb6e817 100644 Binary files a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/copy-paste-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/copy-paste-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/cut-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/cut-cell-jupyterlab-linux.png index 4b7793d7181a..ce7e7f7efde9 100644 Binary files a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/cut-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/cut-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/delete-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/delete-cell-jupyterlab-linux.png index a6944e8cf032..b682734fbbbd 100644 Binary files a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/delete-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/delete-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/insert-cells-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/insert-cells-jupyterlab-linux.png index 63c47797a863..9360e35c0577 100644 Binary files a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/insert-cells-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/insert-cells-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/jump-previous-header-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/jump-previous-header-jupyterlab-linux.png new file mode 100644 index 000000000000..dfa20e73cd1e Binary files /dev/null and b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/jump-previous-header-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/paste-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/paste-cell-jupyterlab-linux.png index df5f065e1c69..48763340ea94 100644 Binary files a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/paste-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/paste-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/run-cell-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/run-cell-jupyterlab-linux.png index 834ab3eee7ef..68863d7ca748 100644 Binary files a/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/run-cell-jupyterlab-linux.png and b/galata/test/jupyterlab/notebook-toolbar.test.ts-snapshots/run-cell-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notebook-trust.test.ts b/galata/test/jupyterlab/notebook-trust.test.ts new file mode 100644 index 000000000000..776ffd8cbd51 --- /dev/null +++ b/galata/test/jupyterlab/notebook-trust.test.ts @@ -0,0 +1,76 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, test } from '@jupyterlab/galata'; + +const fileName = 'trust.ipynb'; +const TRUSTED_SELECTOR = 'svg[data-icon="ui-components:trusted"]'; +const NOT_TRUSTED_SELECTOR = 'svg[data-icon="ui-components:not-trusted"]'; + +test.describe('Notebook Trust', () => { + test.beforeEach(async ({ page }) => { + await page.notebook.createNew(fileName); + }); + + test('Blank Markdown cell does not break trust', async ({ page }) => { + // See https://github.com/jupyterlab/jupyterlab/issues/9765 + + // Add an empty Markdown cell + await page.notebook.addCell('markdown', ''); + // The notebook should be trusted + await expect(page.locator(TRUSTED_SELECTOR)).toHaveCount(1); + await page.notebook.save(); + // Reload page + await page.reload({ waitForIsReady: false }); + // Should still be trusted + await expect(page.locator(TRUSTED_SELECTOR)).toHaveCount(1); + }); + + test('Trust is lost after manually editing notebook', async ({ page }) => { + const browserContext = page.context(); + await browserContext.grantPermissions(['clipboard-read']); + // Add text to first cell + await page.notebook.setCell(0, 'code', 'TEST_TEXT'); + await page.notebook.save(); + // The notebook should be trusted + await expect(page.locator(TRUSTED_SELECTOR)).toHaveCount(1); + await expect(page.locator(NOT_TRUSTED_SELECTOR)).toHaveCount(0); + + // Open notebook in text editor using context menu + await page.click(`.jp-DirListing-item span:has-text("${fileName}")`, { + button: 'right' + }); + await page.hover('text=Open With'); + await page.click('.lm-Menu li[role="menuitem"]:has-text("Editor")'); + const editorContent = await page.waitForSelector( + '.jp-FileEditor .cm-content' + ); + await editorContent.waitForSelector('text=TEST_TEXT'); + const originalContent = await page.evaluate(async () => { + await window.jupyterapp.commands.execute('fileeditor:select-all'); + await window.jupyterapp.commands.execute('fileeditor:cut'); + return navigator.clipboard.readText(); + }); + const newContent = originalContent.replace('TEST_TEXT', 'SUBSTITUTED_TEXT'); + await page.evaluate( + async ([newContent]) => { + await window.jupyterapp.commands.execute( + 'fileeditor:replace-selection', + { text: newContent } + ); + // Save file after changes + await window.jupyterapp.commands.execute('docmanager:save'); + // Close the file editor view of the notebook + await window.jupyterapp.commands.execute('application:close'); + }, + [newContent] + ); + + // Reload page + await page.reload({ waitForIsReady: false }); + + // It should no longer be trusted + await expect(page.locator(TRUSTED_SELECTOR)).toHaveCount(0); + await expect(page.locator(NOT_TRUSTED_SELECTOR)).toHaveCount(1); + }); +}); diff --git a/galata/test/jupyterlab/notebooks/code_notebook.ipynb b/galata/test/jupyterlab/notebooks/code_notebook.ipynb new file mode 100644 index 000000000000..df097ac7060b --- /dev/null +++ b/galata/test/jupyterlab/notebooks/code_notebook.ipynb @@ -0,0 +1,37 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = 1\n", + "b = 2\n", + "c = a + b\n", + "print(c == (a + b))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/galata/test/jupyterlab/notebooks/code_script.py b/galata/test/jupyterlab/notebooks/code_script.py new file mode 100644 index 000000000000..79ee58176a9e --- /dev/null +++ b/galata/test/jupyterlab/notebooks/code_script.py @@ -0,0 +1,4 @@ +a = 1 +b = 2 +c = a + b +print(c == (a + b)) diff --git a/galata/test/jupyterlab/notebooks/completer_panel.py b/galata/test/jupyterlab/notebooks/completer_panel.py new file mode 100644 index 000000000000..13208232c538 --- /dev/null +++ b/galata/test/jupyterlab/notebooks/completer_panel.py @@ -0,0 +1,15 @@ +def option_1(): + """Documentation of 1st option. + + This docstring is intentionally long to fill the documentation panel box. + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vel + auctor felis. Phasellus non risus maximus tortor molestie consectetur. + Suspendisse in mauris eget nunc imperdiet elementum. Morbi consequat velit + at elit suscipit, quis placerat est vulputate. Ut semper leo et fermentum + gravida. Cras dui nisl, varius et lectus quis, maximus facilisis justo. + """ + + +def option_2(): + """Documentation of 2nd option.""" diff --git a/galata/test/jupyterlab/notebooks/css_js_injection.ipynb b/galata/test/jupyterlab/notebooks/css_js_injection.ipynb new file mode 100644 index 000000000000..d0c89fa51598 --- /dev/null +++ b/galata/test/jupyterlab/notebooks/css_js_injection.ipynb @@ -0,0 +1,489 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "4c296a32-1a0c-40e9-8e44-696db2c25eef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "[local link](#Title)" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# dummy\n", + "from IPython.display import Markdown\n", + "\n", + "Markdown('[local link](#Title)')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "f075900d-442f-40b3-842d-9575568d434b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f075910d-442f-40b3-842d-9575568d434b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f075900d-442f-40b3-842d-9575569d434b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "38df214e-2057-446e-b325-4e8c91d9232b", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%html\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "94bab22b-5cfa-40fa-bef8-912a2311e5d6", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%html\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "1cc90740-d880-497a-911f-004ae49bb249", + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "setInterval(() => {\n", + " const injected = document.body.querySelectorAll('[data-origin=\"javascript\"]');\n", + " for(const span of injected) {\n", + " span.remove();\n", + " }\n", + " const cells = document.body.querySelectorAll('.jp-Notebook-cell');\n", + " for(const cell of cells) {\n", + " cell.insertAdjacentHTML('afterbegin', 'JavaScript injected header')\n", + " }\n", + "}, 300)\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + "setInterval(() => {\n", + " const injected = document.body.querySelectorAll('[data-origin=\"javascript\"]');\n", + " for(const span of injected) {\n", + " span.remove();\n", + " }\n", + " const cells = document.body.querySelectorAll('.jp-Notebook-cell');\n", + " for(const cell of cells) {\n", + " cell.insertAdjacentHTML('afterbegin', 'JavaScript injected header')\n", + " }\n", + "}, 300)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.15" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/galata/test/jupyterlab/notebooks/image_notebook.ipynb b/galata/test/jupyterlab/notebooks/image_notebook.ipynb new file mode 100644 index 000000000000..f049cf76a5df --- /dev/null +++ b/galata/test/jupyterlab/notebooks/image_notebook.ipynb @@ -0,0 +1,44 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import Image\n", + "\n", + "global_img = Image(\"WidgetArch.png\")\n", + "\n", + "\n", + "def fc():\n", + " local_img = Image(\"WidgetArch.png\")\n", + " pass\n", + "\n", + "\n", + "fc()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/galata/test/jupyterlab/notebooks/output_scrolling.ipynb b/galata/test/jupyterlab/notebooks/output_scrolling.ipynb new file mode 100644 index 000000000000..34cf548e857c --- /dev/null +++ b/galata/test/jupyterlab/notebooks/output_scrolling.ipynb @@ -0,0 +1,96 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "4315a064-fc29-4183-81b6-fdea37c02102", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "line\n", + "\n" + ] + } + ], + "source": [ + "print('line\\n' * 20)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "1782c124-9e18-4864-b457-acb7a4186105", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "multiple\n" + ] + }, + { + "data": { + "text/plain": [ + "'outputs'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print('multiple')\n", + "'outputs'" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/galata/test/jupyterlab/notebooks/scroll.ipynb b/galata/test/jupyterlab/notebooks/scroll.ipynb new file mode 100644 index 000000000000..1767fd2a1c09 --- /dev/null +++ b/galata/test/jupyterlab/notebooks/scroll.ipynb @@ -0,0 +1,188 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "dfc41e08-3eb7-4331-8521-37bf862b3fba", + "metadata": {}, + "source": [ + "- last cell using heading, legacy format\n", + "- last cell using heading, explicit fragment\n", + "- last cell using cell identifier" + ] + }, + { + "cell_type": "markdown", + "id": "92736779-fc45-4dad-8fdb-ecba14d79e47", + "metadata": {}, + "source": [ + "- penultimate cell using heading, legacy format\n", + "- penultimate cell using heading, explicit fragment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a7a7bbe-bf00-4a94-b961-c177a2d2e25f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ceaf9aff-1445-456b-adb4-62a2b9f5d52e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01aee689-9192-4b8c-99e7-2234d1bfebdb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8662ce35-86ed-4e80-98dd-93cdc1d087b8", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c64e8a12-9488-4d1a-bf3a-dc47c3061dce", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14f5b78f-71d1-4834-8481-ccec72e331cf", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d66568a7-47cd-4bf3-bd48-bca474c7a29a", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89ac20ea-0936-4bc9-88f8-f39c97ef045e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13cc369b-04ac-4c86-8ad1-2417c500c3e2", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19d22c7f-0d2f-4ef9-ae76-2d94edaf6924", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c39a47d-5aac-4d60-b3fd-78213e55ddf9", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c390f49a-96cf-424d-a58c-1bc102c30088", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3abe47af-1f73-4b57-b918-24f560649f4e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e943cf2a-4e4c-4688-8b4f-56f758849ddd", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78668df9-9e32-4295-8878-604b521802d4", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87ef8dfb-c49d-4bc4-8828-7bbed89bb40b", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "1c5beb44-6b15-4c73-a9ed-b4c994ebd9d1", + "metadata": {}, + "source": [ + "# Penultimate cell = this" + ] + }, + { + "cell_type": "markdown", + "id": "fabaec1b-f66d-40e1-82f3-641743d521e0", + "metadata": {}, + "source": [ + "# Last cell" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/galata/test/jupyterlab/notebooks/search.ipynb b/galata/test/jupyterlab/notebooks/search.ipynb new file mode 100644 index 000000000000..832fd81cc46a --- /dev/null +++ b/galata/test/jupyterlab/notebooks/search.ipynb @@ -0,0 +1,143 @@ +{ + "cells": [ + { + "cell_type": "raw", + "id": "41e14fee-d7c9-4454-885d-2518d4ec848c", + "metadata": {}, + "source": [ + "Test with one notebook withr\n", + "\n", + "\n", + "This is a multi line with hits with" + ] + }, + { + "cell_type": "markdown", + "id": "5dc41292-8540-4a89-bc06-f812cc43c66e", + "metadata": { + "tags": [] + }, + "source": [ + "# Test with one notebook withr\n", + "\n", + "This is a [multi line](https://jupyter.org \"with title\") With hits with" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1c89499d-dee1-43b7-b42c-b18a96cf9c4d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "outputs = [\n", + " {\"text/plain\": \"Plain text with\\nmultiple with hits.\"},\n", + " {\n", + " \"application/vnd.jupyter.stderr\": \"\\u001b[0;36m File \\u001b[0;32m\\\"/tmp/ipykernel_20145/2152808028.py\\\"\\u001b[0;36m, line \\u001b[0;32m4\\u001b[0m\\n\\u001b[0;31m This is a multi line with hits witH\\u001b[0m\\n\\u001b[0m \\ ^\\u001b[0m\\n\\u001b[0;31mSyntaxError\\u001b[0m\\u001b[0;31m:\\u001b[0m invalid syntax\\n\"\n", + " },\n", + " {\"text/markdown\": \"# Plain text with\\nmultiple with hits.\"},\n", + " {\n", + " \"text/html\": \"

    Plain text with

    multiple with hits.

    \"\n", + " },\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "04e70d25-05a0-44ae-bcc7-04fab2bd1f55", + "metadata": {}, + "source": [ + "# Title" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5b715d07-c624-4884-bb98-f9ea130d4ca9", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Plain text with\n", + "multiple with hits." + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.stderr": "\u001b[0;36m File \u001b[0;32m\"/tmp/ipykernel_20145/2152808028.py\"\u001b[0;36m, line \u001b[0;32m4\u001b[0m\n\u001b[0;31m This is a multi line with hits with\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "# Plain text with\n", + "multiple with hits." + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "

    Plain text with

    multiple with hits.

    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display\n", + "\n", + "display(*outputs, raw=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4063ad43-470b-436f-b40b-c31008e2b0f5", + "metadata": {}, + "outputs": [], + "source": [ + "from time import sleep\n", + "\n", + "for i in range(3):\n", + " sleep(1)\n", + " print(\"with\")\n", + " print(\"ith with ith\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/galata/test/jupyterlab/notebooks/simple_notebook.ipynb b/galata/test/jupyterlab/notebooks/simple_notebook.ipynb index 9340c535f32a..8927f343a2fc 100644 --- a/galata/test/jupyterlab/notebooks/simple_notebook.ipynb +++ b/galata/test/jupyterlab/notebooks/simple_notebook.ipynb @@ -55,6 +55,7 @@ "outputs": [], "source": [ "import math\n", + "\n", "math.pi / 2" ] } diff --git a/galata/test/jupyterlab/notebooks/toc_notebook.ipynb b/galata/test/jupyterlab/notebooks/toc_notebook.ipynb index ff04a41919f2..0547781b4fee 100644 --- a/galata/test/jupyterlab/notebooks/toc_notebook.ipynb +++ b/galata/test/jupyterlab/notebooks/toc_notebook.ipynb @@ -1,6 +1,23 @@ { "cells": [ { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Out of order sub title 0" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Out of order sub sub title 0a" + ] + }, + { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -18,35 +35,50 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Sub sub title" + "Markdown cell without heading" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "## Sub title 2" + "from time import sleep\n", + "\n", + "sleep(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Sub sub title 1" + "# Sub title 2a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Sub sub title 2" + "### Sub sub title" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sleep(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## IPython: tools for interactive and parallel computing in Python." + "## Sub title 2\n", + "\n", + "### Very long sub title in same cell" ] }, { @@ -55,14 +87,14 @@ "metadata": {}, "outputs": [], "source": [ - "from IPython.display import Image" + "sleep(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Image" + "## Multiple output types" ] }, { @@ -71,7 +103,7 @@ "metadata": {}, "outputs": [], "source": [ - "Image(\"WidgetArch.png\", width=70, height=100)" + "from IPython.display import display" ] }, { @@ -80,7 +112,21 @@ "metadata": {}, "outputs": [], "source": [ - "2 + 2" + "outputs = [\n", + " {\"text/markdown\": \"# Markdown title\\nmultiple with hits.\"},\n", + " {\n", + " \"text/html\": \"

    HTML title

    multiple with hits.

    \"\n", + " },\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "display(*outputs, raw=True)" ] }, { @@ -90,6 +136,7 @@ "outputs": [], "source": [ "import math\n", + "\n", "math.pi / 2" ] } @@ -112,10 +159,10 @@ "pygments_lexer": "ipython3", "version": "3.9.5" }, - "toc-autonumbering": false, - "toc-showcode": false, - "toc-showmarkdowntxt": false, - "toc-showtags": false + "toc": { + "base_numbering": 2, + "skip_h1_title": true + } }, "nbformat": 4, "nbformat_minor": 4 diff --git a/galata/test/jupyterlab/notebooks/toc_scrolling_notebook.ipynb b/galata/test/jupyterlab/notebooks/toc_scrolling_notebook.ipynb new file mode 100644 index 000000000000..65dbcfc00a50 --- /dev/null +++ b/galata/test/jupyterlab/notebooks/toc_scrolling_notebook.ipynb @@ -0,0 +1,110 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e86bd77e-7e48-4941-8cb9-72410d8256aa", + "metadata": {}, + "source": [ + "# regular notebook (not myst)" + ] + }, + { + "cell_type": "markdown", + "id": "d06cb0c2-483b-4781-b283-8212ea667823", + "metadata": {}, + "source": [ + "## a subtitle\n", + "\n", + "Where does it come from?\n", + "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\n" + ] + }, + { + "cell_type": "markdown", + "id": "8541f40d-4f71-48fc-92d4-708063b476ec", + "metadata": {}, + "source": [ + "## another one\n", + "\n", + "Where does it come from?\n", + "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\n" + ] + }, + { + "cell_type": "markdown", + "id": "d896a643-8998-48cf-8a4f-ec2965656e73", + "metadata": {}, + "source": [ + "## yet another\n", + "\n", + "Where does it come from?\n", + "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\n" + ] + }, + { + "cell_type": "markdown", + "id": "a089ea8f-02b8-4b09-af17-aca38782b3c7", + "metadata": {}, + "source": [ + "## let's change\n", + "\n", + "Where does it come from?\n", + "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\n" + ] + }, + { + "cell_type": "markdown", + "id": "6f9ad439-3dc0-410c-9d98-2a9356f839a3", + "metadata": {}, + "source": [ + "## to a less predictible\n", + "\n", + "Where does it come from?\n", + "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\n" + ] + }, + { + "cell_type": "markdown", + "id": "a783fb23-b79c-40c7-b8fe-be597130a3ae", + "metadata": {}, + "source": [ + "## pattern in picking names\n", + "\n", + "Where does it come from?\n", + "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\n" + ] + }, + { + "cell_type": "markdown", + "id": "4e2ae1be-078e-4bf6-974b-6ea6750a74a9", + "metadata": {}, + "source": [ + "## the last one\n", + "\n", + "Where does it come from?\n", + "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/galata/test/jupyterlab/notebooks/vega_notebook.ipynb b/galata/test/jupyterlab/notebooks/vega_notebook.ipynb index 9a7f56bf4b36..f66a322e1a6a 100644 --- a/galata/test/jupyterlab/notebooks/vega_notebook.ipynb +++ b/galata/test/jupyterlab/notebooks/vega_notebook.ipynb @@ -8,27 +8,34 @@ "source": [ "from IPython.display import display\n", "\n", - "display({\n", - " \"application/vnd.vegalite.v3+json\": {\n", - " \"$schema\": \"https://vega.github.io/schema/vega-lite/v3.json\",\n", - " \"description\": \"A simple bar chart with embedded data.\",\n", - " \"data\": {\n", - " \"values\": [\n", - " {\"a\": \"A\", \"b\": 28}, {\"a\": \"B\", \"b\": 55}, {\"a\": \"C\", \"b\": 43},\n", - " {\"a\": \"D\", \"b\": 91}, {\"a\": \"E\", \"b\": 81}, {\"a\": \"F\", \"b\": 53},\n", - " {\"a\": \"G\", \"b\": 19}, {\"a\": \"H\", \"b\": 87}, {\"a\": \"I\", \"b\": 52}\n", - " ]\n", - " },\n", - " \"mark\": \"bar\",\n", - " \"encoding\": {\n", - " \"x\": {\"field\": \"a\", \"type\": \"ordinal\"},\n", - " \"y\": {\"field\": \"b\", \"type\": \"quantitative\"}\n", - " },\n", - " \"metadata\": {\n", - " \"theme\": \"dark\"\n", - " },\n", - " }\n", - "}, raw=True)" + "display(\n", + " {\n", + " \"application/vnd.vegalite.v3+json\": {\n", + " \"$schema\": \"https://vega.github.io/schema/vega-lite/v3.json\",\n", + " \"description\": \"A simple bar chart with embedded data.\",\n", + " \"data\": {\n", + " \"values\": [\n", + " {\"a\": \"A\", \"b\": 28},\n", + " {\"a\": \"B\", \"b\": 55},\n", + " {\"a\": \"C\", \"b\": 43},\n", + " {\"a\": \"D\", \"b\": 91},\n", + " {\"a\": \"E\", \"b\": 81},\n", + " {\"a\": \"F\", \"b\": 53},\n", + " {\"a\": \"G\", \"b\": 19},\n", + " {\"a\": \"H\", \"b\": 87},\n", + " {\"a\": \"I\", \"b\": 52},\n", + " ]\n", + " },\n", + " \"mark\": \"bar\",\n", + " \"encoding\": {\n", + " \"x\": {\"field\": \"a\", \"type\": \"ordinal\"},\n", + " \"y\": {\"field\": \"b\", \"type\": \"quantitative\"},\n", + " },\n", + " \"metadata\": {\"theme\": \"dark\"},\n", + " }\n", + " },\n", + " raw=True,\n", + ")" ] } ], diff --git a/galata/test/jupyterlab/notification.test.ts b/galata/test/jupyterlab/notification.test.ts index 108be8714681..9771f326dda9 100644 --- a/galata/test/jupyterlab/notification.test.ts +++ b/galata/test/jupyterlab/notification.test.ts @@ -72,9 +72,11 @@ test.describe('Toast', () => { const handle = await page.waitForSelector('.Toastify__toast'); - expect(await handle.screenshot()).toMatchSnapshot({ - name: `notification-with-actions.png` - }); + expect(await handle.screenshot({ animations: 'disabled' })).toMatchSnapshot( + { + name: `notification-with-actions.png` + } + ); await Promise.all([ handle.waitForElementState('hidden'), diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-accent-action-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-accent-action-jupyterlab-linux.png index 8b3ffc58a26a..88c5456de3d4 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-accent-action-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-accent-action-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-center-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-center-jupyterlab-linux.png index 1e3b945a1b7d..780928833080 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-center-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-center-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-default-action-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-default-action-jupyterlab-linux.png index 8b3ffc58a26a..5ffb7d73a7cc 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-default-action-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-default-action-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-default-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-default-jupyterlab-linux.png index dc8eb604acec..e863b33b84f7 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-default-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-default-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-error-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-error-jupyterlab-linux.png index e006474caa03..19de89749a4d 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-error-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-error-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-in-progress-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-in-progress-jupyterlab-linux.png index 72ca2d9f50b9..a51cf2ad218f 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-in-progress-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-in-progress-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-info-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-info-jupyterlab-linux.png index 75bf923ed2d8..caa1c69bf1cd 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-info-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-info-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-link-action-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-link-action-jupyterlab-linux.png index b17f6ed5aa5b..a802d065560e 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-link-action-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-link-action-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-success-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-success-jupyterlab-linux.png index ca1816ceb04c..c7d1ff1884a7 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-success-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-success-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-warn-action-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-warn-action-jupyterlab-linux.png index 8b3ffc58a26a..e189e3e05186 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-warn-action-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-warn-action-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-warning-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-warning-jupyterlab-linux.png index bb202beecb23..fb9ec3649cfd 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-warning-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-warning-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-with-actions-jupyterlab-linux.png b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-with-actions-jupyterlab-linux.png index eb2c93cf482a..81229bfe4835 100644 Binary files a/galata/test/jupyterlab/notification.test.ts-snapshots/notification-with-actions-jupyterlab-linux.png and b/galata/test/jupyterlab/notification.test.ts-snapshots/notification-with-actions-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/output-scrolling.test.ts b/galata/test/jupyterlab/output-scrolling.test.ts new file mode 100644 index 000000000000..fc27a406ed8e --- /dev/null +++ b/galata/test/jupyterlab/output-scrolling.test.ts @@ -0,0 +1,78 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { test } from '@jupyterlab/galata'; +import { expect } from '@playwright/test'; +import * as path from 'path'; + +const fileName = 'output_scrolling.ipynb'; + +const cellSelector = '[role="main"] >> .jp-NotebookPanel >> .jp-Cell'; + +test.describe('Output Scrolling', () => { + test.beforeEach(async ({ page, tmpPath }) => { + await page.contents.uploadFile( + path.resolve(__dirname, `./notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + await page.notebook.activate(fileName); + }); + + test.afterEach(async ({ page, tmpPath }) => { + await page.contents.deleteDirectory(tmpPath); + }); + + test('Scrolling mode', async ({ page }) => { + await page.evaluate(() => { + return window.jupyterapp.commands.execute( + 'notebook:enable-output-scrolling' + ); + }); + await page.notebook.selectCells(0); + await expect(page.locator(`${cellSelector} >> nth=0`)).toHaveClass( + /jp-mod-outputsScrolled/ + ); + + const cell = await page.notebook.getCell(0); + + expect(await (await cell.$('.jp-OutputArea')).screenshot()).toMatchSnapshot( + 'cell-output-area-scrolling-mode.png' + ); + + await page.evaluate(() => { + return window.jupyterapp.commands.execute( + 'notebook:disable-output-scrolling' + ); + }); + await expect(page.locator(`${cellSelector} >> nth=0`)).not.toHaveClass( + /jp-mod-outputsScrolled/ + ); + }); + + test('Switching with prompt overlay', async ({ page }) => { + await page + .locator(`${cellSelector} >> nth=1 >> .jp-OutputArea-promptOverlay`) + .hover(); + const cell = await page.notebook.getCell(1); + expect(await cell.screenshot()).toMatchSnapshot( + 'prompt-overlay-hover-normal.png' + ); + await page.click( + `${cellSelector} >> nth=1 >> .jp-OutputArea-promptOverlay` + ); + await expect(page.locator(`${cellSelector} >> nth=1`)).toHaveClass( + /jp-mod-outputsScrolled/ + ); + expect(await cell.screenshot()).toMatchSnapshot( + 'prompt-overlay-hover-scroll.png' + ); + await page.click( + `${cellSelector} >> nth=1 >> .jp-OutputArea-promptOverlay` + ); + await expect(page.locator(`${cellSelector} >> nth=1`)).not.toHaveClass( + /jp-mod-outputsScrolled/ + ); + }); +}); diff --git a/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/cell-output-area-scrolling-mode-jupyterlab-linux.png b/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/cell-output-area-scrolling-mode-jupyterlab-linux.png new file mode 100644 index 000000000000..993cafa056fc Binary files /dev/null and b/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/cell-output-area-scrolling-mode-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/prompt-overlay-hover-normal-jupyterlab-linux.png b/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/prompt-overlay-hover-normal-jupyterlab-linux.png new file mode 100644 index 000000000000..ad0f85ac2956 Binary files /dev/null and b/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/prompt-overlay-hover-normal-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/prompt-overlay-hover-scroll-jupyterlab-linux.png b/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/prompt-overlay-hover-scroll-jupyterlab-linux.png new file mode 100644 index 000000000000..e018c9b55097 Binary files /dev/null and b/galata/test/jupyterlab/output-scrolling.test.ts-snapshots/prompt-overlay-hover-scroll-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/outputarea-stdin.test.ts b/galata/test/jupyterlab/outputarea-stdin.test.ts new file mode 100644 index 000000000000..2efeb9427bc0 --- /dev/null +++ b/galata/test/jupyterlab/outputarea-stdin.test.ts @@ -0,0 +1,55 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, test } from '@jupyterlab/galata'; + +test.describe('Stdin for ipdb', () => { + test.beforeEach(async ({ page }) => { + await page.notebook.createNew(); + }); + + test('Stdin history search', async ({ page }) => { + await page.notebook.setCell(0, 'code', 'raise'); + await page.notebook.addCell('code', '%debug'); + + // Run first cell and proceed to the second one. + await page.notebook.runCell(0); + + // Run the selected (second) cell without proceeding and without waiting + // for it to complete (as it should stay waiting for input). + await page.keyboard.press('Control+Enter'); + + // enter a bunch of nonsense commands into the stdin attached to ipdb + await page.waitForSelector('.jp-Stdin-input'); + await page.keyboard.insertText('foofoo'); + await page.keyboard.press('Enter'); + + await page.waitForSelector('.jp-Stdin-input'); + await page.keyboard.insertText('barbar'); + await page.keyboard.press('Enter'); + + await page.waitForSelector('.jp-Stdin-input'); + await page.keyboard.insertText('bazbaz'); + await page.keyboard.press('Enter'); + + // search for the first nonsense command + await page.waitForSelector('.jp-Stdin-input'); + await page.keyboard.insertText('foo'); + await page.keyboard.press('Control+ArrowUp'); + + // Mask out random kernel temporary file path + // e.g. `/tmp/ipykernel_104185/2235509928.py` + const filePath = await page.$( + '.jp-OutputArea-output :text-matches("/tmp/")' + ); + await filePath.evaluate(node => (node.textContent = '/tmp/masked.py')); + + const imageName = 'stdin-history-search.png'; + const cell = await page.notebook.getCell(1); + expect(await cell.screenshot()).toMatchSnapshot(imageName); + + // Check that the input remains focused and cursor is at the end. + await page.keyboard.insertText('x'); + await expect(page.locator('.jp-Stdin-input')).toHaveValue('foofoox'); + }); +}); diff --git a/galata/test/jupyterlab/outputarea-stdin.test.ts-snapshots/stdin-history-search-jupyterlab-linux.png b/galata/test/jupyterlab/outputarea-stdin.test.ts-snapshots/stdin-history-search-jupyterlab-linux.png new file mode 100644 index 000000000000..414e46ef5362 Binary files /dev/null and b/galata/test/jupyterlab/outputarea-stdin.test.ts-snapshots/stdin-history-search-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/print.test.ts b/galata/test/jupyterlab/print.test.ts new file mode 100644 index 000000000000..02b04c0fde33 --- /dev/null +++ b/galata/test/jupyterlab/print.test.ts @@ -0,0 +1,58 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, test } from '@jupyterlab/galata'; +import * as path from 'path'; + +test.use({ autoGoto: false }); + +const fileName = 'simple_notebook.ipynb'; + +test.describe('Print layout', () => { + test('Notebook', async ({ page, tmpPath }) => { + await page.emulateMedia({ media: 'print' }); + await page.contents.uploadFile( + path.resolve(__dirname, `./notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + await page.contents.uploadFile( + path.resolve(__dirname, './notebooks/WidgetArch.png'), + `${tmpPath}/WidgetArch.png` + ); + + await page.goto(); + + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + + await page.getByText('Python 3 (ipykernel) | Idle').waitFor(); + + await page.notebook.run(); + + let printedNotebookURL = ''; + await Promise.all([ + page.waitForRequest( + async request => { + const url = request.url(); + if (url.match(/\/nbconvert\//) !== null) { + printedNotebookURL = url; + return true; + } + return false; + }, + { timeout: 1000 } + ), + page.keyboard.press('Control+P') + ]); + + const newPage = await page.context().newPage(); + + await newPage.goto(printedNotebookURL, { waitUntil: 'networkidle' }); + + // Wait until MathJax loading message disappears + const mathJaxMessage = newPage.locator('#MathJax_Message'); + await expect(mathJaxMessage).toHaveCount(1); + await mathJaxMessage.waitFor({ state: 'hidden' }); + + expect(await newPage.screenshot()).toMatchSnapshot('printed-notebook.png'); + }); +}); diff --git a/galata/test/jupyterlab/print.test.ts-snapshots/printed-notebook-jupyterlab-linux.png b/galata/test/jupyterlab/print.test.ts-snapshots/printed-notebook-jupyterlab-linux.png new file mode 100644 index 000000000000..e513969fb390 Binary files /dev/null and b/galata/test/jupyterlab/print.test.ts-snapshots/printed-notebook-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/search.test.ts b/galata/test/jupyterlab/search.test.ts index 466146d53dff..2bda65c1a517 100644 --- a/galata/test/jupyterlab/search.test.ts +++ b/galata/test/jupyterlab/search.test.ts @@ -13,13 +13,21 @@ id eleifend eros. In non odio in lorem iaculis sollicitudin. In faucibus ante ut arcu fringilla interdum. Maecenas elit nulla, imperdiet nec blandit et, consequat ut elit.`; -test('Search with a text', async ({ page }) => { - const searchText = 'ipsum'; - await page.menu.clickMenuItem('File>New>Text File'); +function getSelectionRange(textarea: HTMLTextAreaElement) { + return { + start: textarea.selectionStart, + end: textarea.selectionEnd + }; +} - await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); +test.beforeEach(async ({ page }) => { + await page.menu.clickMenuItem('File>New>Text File'); + await page.locator(`[role="main"] >> text=${DEFAULT_NAME}`).waitFor(); + await page.locator('[role="main"] .cm-content').fill(TEST_FILE_CONTENT); +}); - await page.fill('[role="main"] >> textarea', TEST_FILE_CONTENT); +test('Search with a text', async ({ page }) => { + const searchText = 'ipsum'; await page.evaluate(async searchText => { await window.jupyterapp.commands.execute('documentsearch:start', { @@ -27,19 +35,12 @@ test('Search with a text', async ({ page }) => { }); }, searchText); - expect( - await page.locator('input.jp-DocumentSearch-input').inputValue() - ).toEqual(searchText); + await expect(page.locator('[placeholder="Find"]')).toHaveValue(searchText); }); test('Search with a text and replacement', async ({ page }) => { const searchText = 'ipsum'; const replaceText = 'banana'; - await page.menu.clickMenuItem('File>New>Text File'); - - await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); - - await page.fill('[role="main"] >> textarea', TEST_FILE_CONTENT); await page.evaluate( async ([searchText, replaceText]) => { @@ -54,10 +55,42 @@ test('Search with a text and replacement', async ({ page }) => { [searchText, replaceText] ); - expect( - await page.locator('input.jp-DocumentSearch-input').inputValue() - ).toEqual(searchText); - expect( - await page.locator('input.jp-DocumentSearch-replace-entry').inputValue() - ).toEqual(replaceText); + await expect(page.locator('[placeholder="Find"]')).toHaveValue(searchText); + await expect(page.locator('[placeholder="Replace"]')).toHaveValue( + replaceText + ); +}); + +test('Populate search box with selected text', async ({ page }) => { + const imageName = 'text-editor-search-from-selection.png'; + + // Enter first cell + await page.notebook.enterCellEditingMode(0); + + // Go to first line + await page.keyboard.press('PageUp'); + // Select first line + await page.keyboard.press('Home'); + await page.keyboard.press('Control+Shift+ArrowRight'); + // Open search box + await page.keyboard.press('Control+f'); + + // Expect it to be populated with the first word + const inputWithFirstWord = page.locator( + '[placeholder="Find"] >> text="Lorem"' + ); + await expect(inputWithFirstWord).toBeVisible(); + await expect(inputWithFirstWord).toBeFocused(); + // Expect the newly set text to be selected + expect(await inputWithFirstWord.evaluate(getSelectionRange)).toStrictEqual({ + start: 0, + end: 5 + }); + + // Expect the first match to be highlighted + await page.waitForSelector('text=1/2'); + + const tabHandle = await page.activity.getPanel(DEFAULT_NAME); + + expect(await tabHandle.screenshot()).toMatchSnapshot(imageName); }); diff --git a/galata/test/jupyterlab/search.test.ts-snapshots/text-editor-search-from-selection-jupyterlab-linux.png b/galata/test/jupyterlab/search.test.ts-snapshots/text-editor-search-from-selection-jupyterlab-linux.png new file mode 100644 index 000000000000..5daaf0614eae Binary files /dev/null and b/galata/test/jupyterlab/search.test.ts-snapshots/text-editor-search-from-selection-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/settings.test.ts b/galata/test/jupyterlab/settings.test.ts index f3d519802171..d67f37827b24 100644 --- a/galata/test/jupyterlab/settings.test.ts +++ b/galata/test/jupyterlab/settings.test.ts @@ -18,6 +18,18 @@ test('Open the settings editor with a specific search query', async ({ ).toEqual('Command Palette'); await expect(page.locator('.jp-SettingsForm')).toHaveCount(1); + + const pluginList = page.locator('.jp-PluginList'); + + expect(await pluginList.screenshot()).toMatchSnapshot( + 'settings-plugin-list.png' + ); + + const settingsPanel = page.locator('.jp-SettingsPanel'); + + expect(await settingsPanel.screenshot()).toMatchSnapshot( + 'settings-panel.png' + ); }); test.describe('change font-size', () => { @@ -30,7 +42,7 @@ test.describe('change font-size', () => { const createMarkdownFile = async page => { await page.waitForSelector('div[role="main"] >> text=Launcher'); await page.click('.jp-LauncherCard[title="Create a new markdown file"]'); - return await page.waitForSelector('.jp-FileEditor .CodeMirror-code'); + return await page.waitForSelector('.jp-FileEditor .cm-content'); }; const inputMarkdownFile = async (page, markdownFile) => { await markdownFile.focus(); @@ -40,7 +52,7 @@ test.describe('change font-size', () => { }; const getCodeCellFontSize = async page => { const cellElement = await page.$( - 'div.lm-Widget.jp-Cell.jp-CodeCell.jp-Notebook-cell.jp-mod-noOutputs.jp-mod-active.jp-mod-selected .CodeMirror-line' + 'div.lm-Widget.jp-Cell.jp-CodeCell.jp-Notebook-cell.jp-mod-noOutputs.jp-mod-active.jp-mod-selected .cm-line' ); const computedStyle = await page.evaluate( el => getComputedStyle(el), @@ -85,7 +97,7 @@ test.describe('change font-size', () => { await page.waitForSelector('.jp-Notebook-cell'); const cellElement = await page.$( - 'div.lm-Widget.jp-Cell.jp-CodeCell.jp-Notebook-cell.jp-mod-noOutputs.jp-mod-active.jp-mod-selected .CodeMirror-line' + 'div.lm-Widget.jp-Cell.jp-CodeCell.jp-Notebook-cell.jp-mod-noOutputs.jp-mod-active.jp-mod-selected .cm-line' ); const computedStyle = await page.evaluate( el => getComputedStyle(el), @@ -103,7 +115,7 @@ test.describe('change font-size', () => { await page.waitForSelector('.jp-Notebook-cell'); const cellElement = await page.$( - 'div.lm-Widget.jp-Cell.jp-CodeCell.jp-Notebook-cell.jp-mod-noOutputs.jp-mod-active.jp-mod-selected .CodeMirror-line' + 'div.lm-Widget.jp-Cell.jp-CodeCell.jp-Notebook-cell.jp-mod-noOutputs.jp-mod-active.jp-mod-selected .cm-line' ); const computedStyle = await page.evaluate( el => getComputedStyle(el), @@ -116,13 +128,13 @@ test.describe('change font-size', () => { const markdownFile = await createMarkdownFile(page); await inputMarkdownFile(page, markdownFile); await page.evaluate(() => { - return window.jupyterapp.commands.execute('fileeditor:markdown-preview'); + return window.galata.app.commands.execute('fileeditor:markdown-preview'); }); const fontSize = await getMarkdownFontSize(page); await changeCodeFontSize(page, 'Increase Content Font Size'); - await page.waitForSelector('.jp-FileEditor .CodeMirror-code'); + await page.waitForSelector('.jp-FileEditor .cm-content'); const fileElement = await page.$('.jp-RenderedHTMLCommon'); const computedStyle = await page.evaluate( el => getComputedStyle(el), @@ -135,13 +147,13 @@ test.describe('change font-size', () => { const markdownFile = await createMarkdownFile(page); await inputMarkdownFile(page, markdownFile); await page.evaluate(() => { - return window.jupyterapp.commands.execute('fileeditor:markdown-preview'); + return window.galata.app.commands.execute('fileeditor:markdown-preview'); }); const fontSize = await getMarkdownFontSize(page); await changeCodeFontSize(page, 'Decrease Content Font Size'); - await page.waitForSelector('.jp-FileEditor .CodeMirror-code'); + await page.waitForSelector('.jp-FileEditor .cm-content'); const fileElement = await page.$('.jp-RenderedHTMLCommon'); const computedStyle = await page.evaluate( el => getComputedStyle(el), @@ -186,3 +198,31 @@ test.describe('change font-size', () => { expect(computedStyle.fontSize).toEqual(`${fontSize - 1}px`); }); }); + +test('Check codemirror settings can all be set at the same time.', async ({ + page +}) => { + await page.evaluate(async () => { + await window.jupyterapp.commands.execute('settingeditor:open', { + query: 'CodeMirror' + }); + }); + + await expect(page.locator('.jp-SettingsForm')).toHaveCount(1); + + const textList: Array[string] = [ + 'Code Folding', + 'Highlight the active line', + 'Highlight trailing white space', + 'Highlight white space' + ]; + let locators = []; + for (const selectText of textList) { + let locator = page.getByLabel(selectText); + await locator.click(); + locators.push(locator); + } + for (const locator of locators) { + await expect(locator).toBeChecked(); + } +}); diff --git a/galata/test/jupyterlab/settings.test.ts-snapshots/settings-panel-jupyterlab-linux.png b/galata/test/jupyterlab/settings.test.ts-snapshots/settings-panel-jupyterlab-linux.png new file mode 100644 index 000000000000..edecf3198e9d Binary files /dev/null and b/galata/test/jupyterlab/settings.test.ts-snapshots/settings-panel-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/settings.test.ts-snapshots/settings-plugin-list-jupyterlab-linux.png b/galata/test/jupyterlab/settings.test.ts-snapshots/settings-plugin-list-jupyterlab-linux.png new file mode 100644 index 000000000000..d62932bcfb4a Binary files /dev/null and b/galata/test/jupyterlab/settings.test.ts-snapshots/settings-plugin-list-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/shortcuts.test.ts b/galata/test/jupyterlab/shortcuts.test.ts new file mode 100644 index 000000000000..f064e1431481 --- /dev/null +++ b/galata/test/jupyterlab/shortcuts.test.ts @@ -0,0 +1,51 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { test } from '@jupyterlab/galata'; +import { expect } from '@playwright/test'; + +const DUPLICATE_SHORTCUT_WARNING = + 'Skipping this default shortcut because it collides with another default shortcut.'; + +test.use({ autoGoto: false }); + +test('Shortcut commands must exist', async ({ page }) => { + await page.goto(); + + const [shortcuts, commands] = await page.evaluate(async () => { + const shortcuts = window.jupyterapp.commands.keyBindings; + const commandIds = window.jupyterapp.commands.listCommands(); + + return Promise.resolve([shortcuts, commandIds]); + }); + + const missingCommands = shortcuts.filter( + shortcut => !commands.includes(shortcut.command) + ); + + expect(missingCommands).toEqual([]); +}); + +test('Shortcuts must be unique', async ({ page }) => { + const warnings: string[] = []; + + page.on('console', message => { + if (message.type() === 'warning') { + warnings.push(message.text()); + } + }); + + await page.goto(); + + expect( + warnings + .filter(s => s.startsWith(DUPLICATE_SHORTCUT_WARNING)) + // List warning messages only once + .reduce((agg, message) => { + if (!agg.includes(message)) { + agg.push(message); + } + return agg; + }, []) + ).toEqual([]); +}); diff --git a/galata/test/jupyterlab/sidebars.test.ts b/galata/test/jupyterlab/sidebars.test.ts index d1aa7a522f5a..9ee01bba9ad5 100644 --- a/galata/test/jupyterlab/sidebars.test.ts +++ b/galata/test/jupyterlab/sidebars.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { expect, galata, test } from '@jupyterlab/galata'; +import { expect, galata, Handle, test } from '@jupyterlab/galata'; const sidebarIds: galata.SidebarTabId[] = [ 'filebrowser', @@ -11,6 +11,21 @@ const sidebarIds: galata.SidebarTabId[] = [ 'extensionmanager.main-view' ]; +/** + * Add provided text as label on first tab in given tabbar. + * By default we only have icons, but we should test for the + * styling of labels which are used downstream (e.g. sidecar). + */ +async function mockLabelOnFirstTab(tabbar: Handle, text: string) { + await tabbar.$eval( + '.lm-TabBar-tabLabel', + (node: HTMLElement, text: string) => { + node.innerText = text; + }, + text + ); +} + test.describe('Sidebars', () => { sidebarIds.forEach(sidebarId => { test(`Open Sidebar tab ${sidebarId}`, async ({ page }) => { @@ -26,12 +41,51 @@ test.describe('Sidebars', () => { }); }); - test('Toggle Light theme', async ({ page }) => { - await page.theme.setDarkTheme(); + test('File Browser has no unused rules', async ({ page }) => { + await page.sidebar.openTab('filebrowser'); + const clickMenuItem = async (command): Promise => { + const contextmenu = await page.menu.openContextMenu( + '.jp-DirListing-headerItem' + ); + const item = await page.menu.getMenuItemInMenu(contextmenu, command); + await item.click(); + }; + await clickMenuItem('Show File Checkboxes'); + await clickMenuItem('Show File Size Column'); + + await page.notebook.createNew('notebook.ipynb'); + const unusedRules = await page.style.findUnusedStyleRules({ + page, + fragments: ['jp-DirListing', 'jp-FileBrowser'], + exclude: [ + // active during renaming + 'jp-DirListing-editor', + // hidden files + '[data-is-dot]', + // filtering results + '.jp-DirListing-content mark', + // only added after resizing + 'jp-DirListing-narrow' + ] + }); + expect(unusedRules.length).toEqual(0); + }); + + test('Left light tabbar (with text)', async ({ page }) => { await page.theme.setLightTheme(); + const imageName = 'left-light-tabbar-with-text.png'; + const tabbar = await page.sidebar.getTabBar(); + await mockLabelOnFirstTab(tabbar, 'File Browser'); + expect(await tabbar.screenshot()).toMatchSnapshot(imageName.toLowerCase()); + }); - expect(await page.theme.getTheme()).toEqual('JupyterLab Light'); + test('Right dark tabbar (with text)', async ({ page }) => { + await page.theme.setDarkTheme(); + const imageName = 'right-dark-tabbar-with-text.png'; + const tabbar = await page.sidebar.getTabBar('right'); + await mockLabelOnFirstTab(tabbar, 'Property Inspector'); + expect(await tabbar.screenshot()).toMatchSnapshot(imageName.toLowerCase()); }); test('Move File Browser to right', async ({ page }) => { diff --git a/galata/test/jupyterlab/sidebars.test.ts-snapshots/filebrowser-right-jupyterlab-linux.png b/galata/test/jupyterlab/sidebars.test.ts-snapshots/filebrowser-right-jupyterlab-linux.png index ec50b59229ab..dde27caa4a09 100644 Binary files a/galata/test/jupyterlab/sidebars.test.ts-snapshots/filebrowser-right-jupyterlab-linux.png and b/galata/test/jupyterlab/sidebars.test.ts-snapshots/filebrowser-right-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/sidebars.test.ts-snapshots/left-light-tabbar-with-text-jupyterlab-linux.png b/galata/test/jupyterlab/sidebars.test.ts-snapshots/left-light-tabbar-with-text-jupyterlab-linux.png new file mode 100644 index 000000000000..e0f29843ec67 Binary files /dev/null and b/galata/test/jupyterlab/sidebars.test.ts-snapshots/left-light-tabbar-with-text-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-extensionmanager-main-view-jupyterlab-linux.png b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-extensionmanager-main-view-jupyterlab-linux.png index a480747a0f8b..1b01d08b5d29 100644 Binary files a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-extensionmanager-main-view-jupyterlab-linux.png and b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-extensionmanager-main-view-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-filebrowser-jupyterlab-linux.png b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-filebrowser-jupyterlab-linux.png index 272445928edb..bb0522632d8d 100644 Binary files a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-filebrowser-jupyterlab-linux.png and b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-filebrowser-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-jp-property-inspector-jupyterlab-linux.png b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-jp-property-inspector-jupyterlab-linux.png index cbf9ad0913e8..d5e1350c6d27 100644 Binary files a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-jp-property-inspector-jupyterlab-linux.png and b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-jp-property-inspector-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-jp-running-sessions-jupyterlab-linux.png b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-jp-running-sessions-jupyterlab-linux.png index f80fe0516849..946c0496c04a 100644 Binary files a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-jp-running-sessions-jupyterlab-linux.png and b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-jp-running-sessions-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-table-of-contents-jupyterlab-linux.png b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-table-of-contents-jupyterlab-linux.png index 0d405f7789fd..ec6ef830ceeb 100644 Binary files a/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-table-of-contents-jupyterlab-linux.png and b/galata/test/jupyterlab/sidebars.test.ts-snapshots/opened-sidebar-table-of-contents-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/sidebars.test.ts-snapshots/right-dark-tabbar-with-text-jupyterlab-linux.png b/galata/test/jupyterlab/sidebars.test.ts-snapshots/right-dark-tabbar-with-text-jupyterlab-linux.png new file mode 100644 index 000000000000..9989151e0f1b Binary files /dev/null and b/galata/test/jupyterlab/sidebars.test.ts-snapshots/right-dark-tabbar-with-text-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/styles.test.ts b/galata/test/jupyterlab/styles.test.ts index 4917d6ebb8ba..406f23f66813 100644 --- a/galata/test/jupyterlab/styles.test.ts +++ b/galata/test/jupyterlab/styles.test.ts @@ -3,7 +3,7 @@ import { expect, test } from '@jupyterlab/galata'; -// posssibly incomplete (as new tags get added) list of HTML tags as defined in HTML standards (including deprecated elements) +// possibly incomplete (as new tags get added) list of HTML tags as defined in HTML standards (including deprecated elements) const standardHTMLTags = new Set([ 'a', 'abbr', @@ -146,7 +146,7 @@ test.describe('CSS Selectors', () => { await page.theme.setLightTheme(); break; default: - throw new Error(`Unknown theme ${theme}`); + expect(false); } // Create a new notebook and add a MathJax 2 element to ensure that @@ -170,13 +170,7 @@ test.describe('CSS Selectors', () => { const allTags = new Set([...standardHTMLTags, ...detectedTags]); - const selectors: string[] = await page.evaluate(() => - [...document.querySelectorAll('style')] - .map(style => [...style.sheet.cssRules]) - .flat() - .filter((rule: CSSRule) => rule instanceof CSSStyleRule) - .map((rule: CSSStyleRule) => rule.selectorText) - ); + const selectors: string[] = await page.style.collectAllSelectors(); const matcher = new RegExp( ':hover.*\\s+(' + [...allTags].join('|') + ')($|\\s)' ); @@ -186,14 +180,6 @@ test.describe('CSS Selectors', () => { for (const selectorGroup of selectors) { for (const selector of selectorGroup.split(',')) { if (selector.match(matcher)) { - if ( - selector.includes('.bp3-control') || - selector.includes('.bp3-interactive') - ) { - // Ignore problematic Blueprint styles on 3.4.x - those were removed in 4.0, - // and are not as problematic since they only match against `input` and `td`. - continue; - } matchedSelectors.push(selector); } } diff --git a/galata/test/jupyterlab/terminal.test.ts b/galata/test/jupyterlab/terminal.test.ts index df261c308c98..e026415b6dad 100644 --- a/galata/test/jupyterlab/terminal.test.ts +++ b/galata/test/jupyterlab/terminal.test.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import { expect, test } from '@jupyterlab/galata'; const TERMINAL_SELECTOR = '.jp-Terminal'; @@ -112,16 +117,13 @@ test('Terminal web link', async ({ page, tmpPath }) => { await page.keyboard.press('Enter'); await page.waitForTimeout(1000); await Promise.all([ - terminal.locator('.jp-Terminal-body.xterm-cursor-pointer').waitFor(), - terminal - .locator('canvas') - .last() - .hover({ - position: { - x: 60, - y: 23 - } - }) + terminal.locator('.jp-Terminal-body .xterm-cursor-pointer').waitFor(), + terminal.locator('canvas.xterm-cursor-layer').hover({ + position: { + x: 60, + y: 23 + } + }) ]); expect(await terminal.screenshot()).toMatchSnapshot('web-links-term.png'); }); diff --git a/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-inherit-jupyterlab-linux.png b/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-inherit-jupyterlab-linux.png index ee868f89f694..5f75dd994b1d 100644 Binary files a/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-inherit-jupyterlab-linux.png and b/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-inherit-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/terminal.test.ts-snapshots/launcher-term-jupyterlab-linux.png b/galata/test/jupyterlab/terminal.test.ts-snapshots/launcher-term-jupyterlab-linux.png index 0ed5aff85885..d9033cf0bcf2 100644 Binary files a/galata/test/jupyterlab/terminal.test.ts-snapshots/launcher-term-jupyterlab-linux.png and b/galata/test/jupyterlab/terminal.test.ts-snapshots/launcher-term-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/texteditor.test.ts b/galata/test/jupyterlab/texteditor.test.ts index 802bedf25fa6..501a083bf874 100644 --- a/galata/test/jupyterlab/texteditor.test.ts +++ b/galata/test/jupyterlab/texteditor.test.ts @@ -20,30 +20,20 @@ test.describe('Text Editor Tests', () => { const imageName = 'text-editor-rulers.png'; await page.menu.clickMenuItem('File>New>Text File'); - await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); + await page.getByRole('main').getByText(DEFAULT_NAME).waitFor(); - await page.menu.clickMenuItem('Settings>Advanced Settings Editor'); + await page.menu.clickMenuItem('Settings>Settings Editor'); - await page.waitForSelector('text=Text Editor'); - await page.click('text=Text Editor'); + await page + .getByRole('tab', { name: 'Text Editor' }) + .getByText('Text Editor') + .click(); // Add two rulers - await page.click('text="Add"'); - await page.click( - '[id="jp-SettingsEditor-@jupyterlab/fileeditor-extension:plugin_editorConfig_rulers_0"]' - ); - await page.type( - '[id="jp-SettingsEditor-@jupyterlab/fileeditor-extension:plugin_editorConfig_rulers_0"]', - '50' - ); - await page.click('text="Add"'); - await page.click( - '[id="jp-SettingsEditor-@jupyterlab/fileeditor-extension:plugin_editorConfig_rulers_1"]' - ); - await page.type( - '[id="jp-SettingsEditor-@jupyterlab/fileeditor-extension:plugin_editorConfig_rulers_1"]', - '75' - ); + await page.locator('#root').getByRole('button', { name: 'Add' }).click(); + await page.locator('input[id="root_rulers_0"]').type('50'); + await page.locator('#root').getByRole('button', { name: 'Add' }).click(); + await page.locator('input[id="root_rulers_1"]').type('75'); await page.activity.activateTab(DEFAULT_NAME); @@ -52,25 +42,57 @@ test.describe('Text Editor Tests', () => { expect(await tabHandle.screenshot()).toMatchSnapshot(imageName); }); + test('Selection in highlighted line', async ({ page }) => { + const imageName = 'text-editor-active-line-with-selection.png'; + await page.evaluate(async () => { + await window.jupyterapp.commands.execute('settingeditor:open', { + query: 'Text Editor' + }); + }); + + let locator = page.getByLabel('Highlight the active line'); + await locator.click(); + + await page.menu.clickMenuItem('File>New>Text File'); + + await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); + + await page.type( + '.cm-content', + 'Not active\nActive line with >>selected text<<\nNot active' + ); + + await page.keyboard.press('ArrowUp'); + await page.keyboard.press('End'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + for (let i = 0; i < 13; i++) { + await page.keyboard.press('Shift+ArrowLeft'); + } + expect( + await page.locator('.jp-FileEditorCodeWrapper .cm-content').screenshot() + ).toMatchSnapshot(imageName, { threshold: 0.01 }); + }); + test('Go to line with argument', async ({ page }) => { const imageName = 'go-to-line-editor.png'; await page.menu.clickMenuItem('File>New>Text File'); await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); - await page.fill( - '[role="main"] >> textarea', + await page.type( + '.cm-content', `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam urna -libero, dictum a egestas non, placerat vel neque. In imperdiet iaculis fermentum. -Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia -Curae; Cras augue tortor, tristique vitae varius nec, dictum eu lectus. Pellentesque -id eleifend eros. In non odio in lorem iaculis sollicitudin. In faucibus ante ut -arcu fringilla interdum. Maecenas elit nulla, imperdiet nec blandit et, consequat +libero, dictum a egestas non, placerat vel neque. In imperdiet iaculis fermentum. +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia +Curae; Cras augue tortor, tristique vitae varius nec, dictum eu lectus. Pellentesque +id eleifend eros. In non odio in lorem iaculis sollicitudin. In faucibus ante ut +arcu fringilla interdum. Maecenas elit nulla, imperdiet nec blandit et, consequat ut elit.` ); await page.evaluate(async () => { - await window.jupyterapp.commands.execute('codemirror:go-to-line', { + await window.jupyterapp.commands.execute('fileeditor:go-to-line', { line: 2, column: 8 }); diff --git a/galata/test/jupyterlab/texteditor.test.ts-snapshots/go-to-line-editor-jupyterlab-linux.png b/galata/test/jupyterlab/texteditor.test.ts-snapshots/go-to-line-editor-jupyterlab-linux.png index ac9d84b97241..cf1527f4e5a8 100644 Binary files a/galata/test/jupyterlab/texteditor.test.ts-snapshots/go-to-line-editor-jupyterlab-linux.png and b/galata/test/jupyterlab/texteditor.test.ts-snapshots/go-to-line-editor-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-active-line-with-selection-jupyterlab-linux.png b/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-active-line-with-selection-jupyterlab-linux.png new file mode 100644 index 000000000000..5911f2a8ff17 Binary files /dev/null and b/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-active-line-with-selection-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-jupyterlab-linux.png b/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-jupyterlab-linux.png index 6d4eee2cb441..a4b90daedff1 100644 Binary files a/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-jupyterlab-linux.png and b/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-rulers-jupyterlab-linux.png b/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-rulers-jupyterlab-linux.png index a1819898f635..a4b90daedff1 100644 Binary files a/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-rulers-jupyterlab-linux.png and b/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-rulers-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/toc-running.test.ts b/galata/test/jupyterlab/toc-running.test.ts index 60d9d1bbc717..5ac557858eba 100644 --- a/galata/test/jupyterlab/toc-running.test.ts +++ b/galata/test/jupyterlab/toc-running.test.ts @@ -6,17 +6,19 @@ import { expect, test } from '@jupyterlab/galata'; test.describe('ToC Running indicator', () => { test.beforeEach(async ({ page }) => { await page.notebook.createNew(); - await page.notebook.addCell('markdown', '# Title 1'); + await page.notebook.setCell(0, 'markdown', '# Title 1'); await page.notebook.addCell('code', 'from time import sleep'); await page.notebook.addCell('code', 'sleep(2)'); await page.notebook.addCell('markdown', '## Title 1.1'); + await page.notebook.addCell('markdown', 'No heading'); await page.notebook.addCell('code', 'sleep(2)'); await page.notebook.addCell('markdown', '## Title 1.2'); await page.notebook.addCell('code', 'sleep(1)'); - await page.notebook.run(); - await page.sidebar.openTab('table-of-contents'); + await page.waitForSelector( + '.jp-TableOfContents-content[data-document-type="notebook"] >> text=Title 1.2' + ); }); test('should display running indicators', async ({ page }) => { @@ -24,7 +26,6 @@ test.describe('ToC Running indicator', () => { await page.sidebar.getTabPosition('table-of-contents') ); const executed = page.notebook.run(); - await tocPanel.waitForSelector('[data-running="1"]'); expect(await tocPanel.screenshot()).toMatchSnapshot( 'toc-running-indicators.png' @@ -39,9 +40,11 @@ test.describe('ToC Running indicator', () => { const tocPanel = await page.sidebar.getContentPanel( await page.sidebar.getTabPosition('table-of-contents') ); + await page.notebook.run(); + // Collapse ToC await page.click( - '[aria-label="Table of Contents section"] li >> :nth-match(div, 3)' + '[aria-label="Table of Contents section"] >> button:left-of(:text("Title 1"))' ); const executed = page.notebook.runCell(5); @@ -53,22 +56,4 @@ test.describe('ToC Running indicator', () => { await executed; }); - - test('should display running indicator in prompt', async ({ page }) => { - const tocPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('table-of-contents') - ); - const toolbarButtons = await tocPanel.$$('.toc-toolbar .toc-toolbar-icon'); - await toolbarButtons[0].click(); - - const tocEntry = page - .locator('.jp-TableOfContents-content .jp-tocItem') - .nth(2) - .locator('.toc-code-cell-prompt'); - const executed = page.notebook.runCell(3); - - await expect(tocEntry).toHaveText('[*]: '); - - await executed; - }); }); diff --git a/galata/test/jupyterlab/toc-running.test.ts-snapshots/toc-running-indicator-top-level-jupyterlab-linux.png b/galata/test/jupyterlab/toc-running.test.ts-snapshots/toc-running-indicator-top-level-jupyterlab-linux.png index e96b35d31409..b174608fc6e3 100644 Binary files a/galata/test/jupyterlab/toc-running.test.ts-snapshots/toc-running-indicator-top-level-jupyterlab-linux.png and b/galata/test/jupyterlab/toc-running.test.ts-snapshots/toc-running-indicator-top-level-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/toc-running.test.ts-snapshots/toc-running-indicators-jupyterlab-linux.png b/galata/test/jupyterlab/toc-running.test.ts-snapshots/toc-running-indicators-jupyterlab-linux.png index 861f6b5b8522..c9111aa4d649 100644 Binary files a/galata/test/jupyterlab/toc-running.test.ts-snapshots/toc-running-indicators-jupyterlab-linux.png and b/galata/test/jupyterlab/toc-running.test.ts-snapshots/toc-running-indicators-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/toc-scrolling.test.ts b/galata/test/jupyterlab/toc-scrolling.test.ts new file mode 100644 index 000000000000..8e32ef167818 --- /dev/null +++ b/galata/test/jupyterlab/toc-scrolling.test.ts @@ -0,0 +1,54 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; +import * as path from 'path'; + +const fileName = 'toc_scrolling_notebook.ipynb'; + +test.use({ tmpPath: 'test-toc' }); + +test.describe('Table of Contents scrolling to heading', () => { + test.beforeAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); + await contents.uploadFile( + path.resolve(__dirname, `./notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + }); + + test.beforeEach(async ({ page, tmpPath }) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + await page.notebook.activate(fileName); + + await page.sidebar.openTab('table-of-contents'); + }); + + test.afterEach(async ({ page }) => { + await page.notebook.close(true); + }); + + test.afterAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); + await contents.deleteDirectory(tmpPath); + }); + + test('Notebook scrolls to heading', async ({ page }) => { + await page.notebook.selectCells(0); + + await page.sidebar.getContentPanel( + await page.sidebar.getTabPosition('table-of-contents') + ); + + await page + .locator('.jp-TableOfContents-tree >> text="the last one"') + .click({ + button: 'left' + }); + + const nbPanel = await page.notebook.getNotebookInPanel(); + expect(await nbPanel.screenshot()).toMatchSnapshot( + 'scrolled-to-bottom-heading.png' + ); + }); +}); diff --git a/galata/test/jupyterlab/toc-scrolling.test.ts-snapshots/scrolled-to-bottom-heading-jupyterlab-linux.png b/galata/test/jupyterlab/toc-scrolling.test.ts-snapshots/scrolled-to-bottom-heading-jupyterlab-linux.png new file mode 100644 index 000000000000..e0da0d5e014b Binary files /dev/null and b/galata/test/jupyterlab/toc-scrolling.test.ts-snapshots/scrolled-to-bottom-heading-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/toc.test.ts b/galata/test/jupyterlab/toc.test.ts index 29cf667afa5a..abc994cb61b6 100644 --- a/galata/test/jupyterlab/toc.test.ts +++ b/galata/test/jupyterlab/toc.test.ts @@ -8,88 +8,35 @@ const fileName = 'toc_notebook.ipynb'; test.use({ tmpPath: 'test-toc' }); -test.describe.serial('Table of Contents', () => { - test.beforeAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); +test.describe('Table of Contents', () => { + test.beforeAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.uploadFile( path.resolve(__dirname, `./notebooks/${fileName}`), `${tmpPath}/${fileName}` ); - await contents.uploadFile( - path.resolve(__dirname, './notebooks/WidgetArch.png'), - `${tmpPath}/WidgetArch.png` - ); }); test.beforeEach(async ({ page, tmpPath }) => { await page.notebook.openByPath(`${tmpPath}/${fileName}`); await page.notebook.activate(fileName); + + await page.sidebar.openTab('table-of-contents'); + + await page.click('.jp-toc-numberingButton'); }); test.afterEach(async ({ page }) => { await page.notebook.close(true); }); - test.afterAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); + test.afterAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.deleteDirectory(tmpPath); }); - test('Add tags', async ({ page }) => { - await page.sidebar.openTab('jp-property-inspector'); - const imageName = 'add-tags.png'; - const tagInputSelector = 'div.tag-holder input.add-tag'; - let piPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('jp-property-inspector') - ); - let addTagInput = await piPanel.$(tagInputSelector); - await addTagInput.click(); - await page.keyboard.insertText('tag1'); - await page.keyboard.press('Enter'); - addTagInput = await piPanel.$(tagInputSelector); - await addTagInput.click(); - await page.keyboard.insertText('tag2'); - await page.keyboard.press('Enter'); - await page.notebook.save(); - - const cellTagsPanel = await piPanel.$('.jp-NotebookTools-tool.jp-TagTool'); - - expect(await cellTagsPanel.screenshot()).toMatchSnapshot(imageName); - }); - - test('Assign tags to cells', async ({ page }) => { - await page.notebook.selectCells(6); - - await page.sidebar.openTab('jp-property-inspector'); - let piPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('jp-property-inspector') - ); - const tags = await piPanel.$$('.lm-Widget.tag'); - expect(tags.length).toBe(3); // including Add Tag - await tags[0].click(); - - await page.notebook.activate(fileName); - await page.notebook.selectCells(9); - - await page.sidebar.openTab('jp-property-inspector'); - await tags[1].click(); - - await page.notebook.activate(fileName); - await page.notebook.selectCells(11); - - await page.sidebar.openTab('jp-property-inspector'); - await tags[0].click(); - await tags[1].click(); - - await page.notebook.activate(fileName); - await page.notebook.save(); - }); - test('Open Table of Contents panel', async ({ page }) => { const imageName = 'toc-panel.png'; - await page.notebook.selectCells(0); - - await page.sidebar.openTab('table-of-contents'); const tocPanel = await page.sidebar.getContentPanel( await page.sidebar.getTabPosition('table-of-contents') ); @@ -97,137 +44,53 @@ test.describe.serial('Table of Contents', () => { expect(await tocPanel.screenshot()).toMatchSnapshot(imageName); }); - test('Toggle code', async ({ page }) => { - await page.notebook.selectCells(0); - await page.sidebar.openTab('table-of-contents'); - - const tocPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('table-of-contents') - ); - const toolbarButtons = await tocPanel.$$('.toc-toolbar .toc-toolbar-icon'); - expect(toolbarButtons.length).toBe(4); - - const imageName = 'toggle-code.png'; - await toolbarButtons[0].click(); - - expect(await tocPanel.screenshot()).toMatchSnapshot(imageName); - await toolbarButtons[0].click(); - }); - - test('Toggle markdown', async ({ page }) => { - await page.notebook.selectCells(0); - await page.sidebar.openTab('table-of-contents'); - - const tocPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('table-of-contents') - ); - const toolbarButtons = await tocPanel.$$('.toc-toolbar .toc-toolbar-icon'); - expect(toolbarButtons.length).toBe(4); - - const imageName = 'toggle-markdown.png'; - await toolbarButtons[1].click(); - - expect(await tocPanel.screenshot()).toMatchSnapshot(imageName); - await toolbarButtons[1].click(); - }); - test('Toggle list', async ({ page }) => { await page.notebook.selectCells(0); - await page.sidebar.openTab('table-of-contents'); const tocPanel = await page.sidebar.getContentPanel( await page.sidebar.getTabPosition('table-of-contents') ); - const toolbarButtons = await tocPanel.$$('.toc-toolbar .toc-toolbar-icon'); - expect(toolbarButtons.length).toBe(4); - - const imageName = 'toggle-numbered-list.png'; - await toolbarButtons[2].click(); - - expect(await tocPanel.screenshot()).toMatchSnapshot(imageName); - await toolbarButtons[2].click(); - }); - - test('Toggle show tags', async ({ page }) => { - await page.notebook.selectCells(0); - await page.sidebar.openTab('table-of-contents'); - - const tocPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('table-of-contents') + const numberingButton = await tocPanel.$$( + 'button[data-command="toc:display-numbering"]' ); - const toolbarButtons = await tocPanel.$$('.toc-toolbar .toc-toolbar-icon'); - expect(toolbarButtons.length).toBe(4); - - // toggle code and markdown - await toolbarButtons[0].click(); - await toolbarButtons[1].click(); + expect(numberingButton.length).toBe(1); - const imageName = 'show-tags.png'; - await toolbarButtons[3].click(); - - expect(await tocPanel.screenshot()).toMatchSnapshot(imageName); - }); - - test('Toggle tag 1', async ({ page }) => { - await page.notebook.selectCells(0); - await page.sidebar.openTab('table-of-contents'); - - const tocPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('table-of-contents') - ); - const toolbarButtons = await tocPanel.$$('.toc-toolbar .toc-toolbar-icon'); - // toggle code and markdown - await toolbarButtons[0].click(); - await toolbarButtons[1].click(); - await toolbarButtons[3].click(); - - const tags = await tocPanel.$$('.toc-tag'); - expect(tags.length).toBe(2); - - const imageName = 'toggle-tag-1.png'; - await tags[0].click(); + const imageName = 'toggle-numbered-list.png'; + await numberingButton[0].click(); expect(await tocPanel.screenshot()).toMatchSnapshot(imageName); - await tags[0].click(); }); - test('Toggle tag 2', async ({ page }) => { + test('Notebook context menu', async ({ page }) => { await page.notebook.selectCells(0); - await page.sidebar.openTab('table-of-contents'); const tocPanel = await page.sidebar.getContentPanel( await page.sidebar.getTabPosition('table-of-contents') ); - const toolbarButtons = await tocPanel.$$('.toc-toolbar .toc-toolbar-icon'); - // toggle code and markdown - await toolbarButtons[0].click(); - await toolbarButtons[1].click(); - await toolbarButtons[3].click(); - - const tags = await tocPanel.$$('.toc-tag'); - const imageName = 'toggle-tag-2.png'; - await tags[1].click(); + await Promise.all([ + page.locator( + '.jp-TableOfContents-tree >> .jp-tocItem-active >> text="2. Multiple output types"' + ), + page + .locator('.jp-TableOfContents-tree >> text="2. Multiple output types"') + .click({ + button: 'right' + }) + ]); - expect(await tocPanel.screenshot()).toMatchSnapshot(imageName); - await tags[1].click(); - }); - - test('Open context menu', async ({ page }) => { - await page.notebook.selectCells(0); - await page.sidebar.openTab('table-of-contents'); + const menu = await page.menu.getOpenMenu(); - const tocPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('table-of-contents') - ); + await ( + await menu.$('text=Select and Run Cell(s) for this Heading') + ).click(); - await (await tocPanel.$('li > .toc-level-size-1')).click({ - button: 'right' - }); + await page + .locator('.jp-TableOfContents-tree >> text="2. HTML title"') + .waitFor(); - const menu = await page.menu.getOpenMenu(); - expect(await menu.screenshot()).toMatchSnapshot( - 'notebook-context-menu.png' + expect(await tocPanel.screenshot()).toMatchSnapshot( + 'notebook-output-headings.png' ); }); }); diff --git a/galata/test/jupyterlab/toc.test.ts-snapshots/notebook-output-headings-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/notebook-output-headings-jupyterlab-linux.png new file mode 100644 index 000000000000..621ec317a9b9 Binary files /dev/null and b/galata/test/jupyterlab/toc.test.ts-snapshots/notebook-output-headings-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/toc.test.ts-snapshots/toc-panel-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/toc-panel-jupyterlab-linux.png index 1ddb08314337..611d95d0282a 100644 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/toc-panel-jupyterlab-linux.png and b/galata/test/jupyterlab/toc.test.ts-snapshots/toc-panel-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-numbered-list-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-numbered-list-jupyterlab-linux.png index dd805f92e6d4..7df306ca81e1 100644 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-numbered-list-jupyterlab-linux.png and b/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-numbered-list-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/toolbars.test.ts b/galata/test/jupyterlab/toolbars.test.ts new file mode 100644 index 000000000000..3fe9be02cdd7 --- /dev/null +++ b/galata/test/jupyterlab/toolbars.test.ts @@ -0,0 +1,39 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { test } from '@jupyterlab/galata'; +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; +import { expect } from '@playwright/test'; + +const toolbars: string[][] = [ + ['@jupyterlab/csvviewer-extension:csv', 'toolbar'], + ['@jupyterlab/csvviewer-extension:tsv', 'toolbar'], + ['@jupyterlab/fileeditor-extension:plugin', 'toolbar'], + ['@jupyterlab/htmlviewer-extension:plugin', 'toolbar'], + ['@jupyterlab/notebook-extension:panel', 'toolbar'] +]; + +toolbars.forEach(([plugin, parameter]) => { + test(`Toolbar commands for ${plugin} must exists`, async ({ page }) => { + const [toolbarItems, commands] = await page.evaluate( + async ([plugin, parameter]) => { + const settings = await window.galata.getPlugin( + '@jupyterlab/apputils-extension:settings' + ); + const toolbar = await settings.get(plugin, parameter); + + const commandIds = window.jupyterapp.commands.listCommands(); + return Promise.resolve([ + toolbar.composite as ISettingRegistry.IToolbarItem[], + commandIds + ]); + }, + [plugin, parameter] + ); + + const missingCommands = toolbarItems.filter( + item => item.command !== undefined && !commands.includes(item.command) + ); + expect(missingCommands).toEqual([]); + }); +}); diff --git a/galata/test/jupyterlab/windowed-notebook.test.ts b/galata/test/jupyterlab/windowed-notebook.test.ts new file mode 100644 index 000000000000..ed21c0fe135a --- /dev/null +++ b/galata/test/jupyterlab/windowed-notebook.test.ts @@ -0,0 +1,297 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. +import { expect, galata, test } from '@jupyterlab/galata'; +import * as path from 'path'; + +const fileName = 'windowed_notebook.ipynb'; +const injectionFile = 'css_js_injection.ipynb'; + +test.use({ + mockSettings: { + ...galata.DEFAULT_SETTINGS, + '@jupyterlab/notebook-extension:tracker': { + ...galata.DEFAULT_SETTINGS['@jupyterlab/notebook-extension:tracker'], + windowingMode: 'full' + } + } +}); + +test.beforeEach(async ({ page, tmpPath }) => { + await page.contents.uploadFile( + path.resolve(__dirname, `../galata/notebooks/${fileName}`), + `${tmpPath}/${fileName}` + ); + await page.contents.uploadFile( + path.resolve(__dirname, `./notebooks/${injectionFile}`), + `${tmpPath}/${injectionFile}` + ); +}); + +test('should not update height when hiding', async ({ page, tmpPath }) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + + // Wait to ensure the rendering logic is stable. + await page.waitForTimeout(200); + + const h = await page.notebook.getNotebookInPanel(); + const initialHeight = parseInt( + (await h?.$$eval( + '.jp-WindowedPanel-inner', + nodes => nodes[0].style.height + )) ?? '0', + 10 + ); + + expect(initialHeight).toBeGreaterThan(0); + + await page.menu.clickMenuItem('File>New Launcher'); + + const innerHeight = + (await h?.$$eval( + '.jp-WindowedPanel-inner', + nodes => nodes[0].style.height + )) ?? '-1'; + + expect(parseInt(innerHeight, 10)).toEqual(initialHeight); +}); + +test('should hide first code cell when scrolling down', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + + const h = await page.notebook.getNotebookInPanel(); + const firstCellSelector = '.jp-Cell[data-windowed-list-index="0"]'; + const firstCell = await h!.waitForSelector(firstCellSelector); + + const bbox = await h!.boundingBox(); + await page.mouse.move(bbox!.x, bbox!.y); + await Promise.all([ + firstCell.waitForElementState('hidden'), + page.mouse.wheel(0, 600) + ]); + + // Check the content contains only the output + expect(await firstCell.textContent()).toEqual('[16]:local link\n'); +}); + +test('should reattached a code code cell when scrolling back into the viewport', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + + const h = await page.notebook.getNotebookInPanel(); + const firstCellSelector = '.jp-Cell[data-windowed-list-index="0"]'; + const firstCell = await h!.waitForSelector(firstCellSelector); + + const bbox = await h!.boundingBox(); + await page.mouse.move(bbox!.x, bbox!.y); + await Promise.all([ + firstCell.waitForElementState('hidden'), + h!.waitForSelector('.jp-MarkdownCell[data-windowed-list-index="6"]'), + page.mouse.wheel(0, 1200) + ]); + + await Promise.all([ + firstCell.waitForElementState('visible'), + page.mouse.wheel(0, -1200) + ]); + + // Check that the input area is back + expect(await firstCell.waitForSelector('.jp-InputArea')).toBeDefined(); +}); + +test('should detach a markdown code cell when scrolling out of the viewport', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + + const h = await page.notebook.getNotebookInPanel(); + const mdCellSelector = '.jp-MarkdownCell[data-windowed-list-index="2"]'; + const mdCell = await h!.waitForSelector(mdCellSelector); + + const bbox = await h!.boundingBox(); + await page.mouse.move(bbox!.x, bbox!.y); + await Promise.all([ + mdCell.waitForElementState('hidden'), + page.mouse.wheel(0, 1200) + ]); + + let found = true; + try { + await h!.waitForSelector(mdCellSelector, { timeout: 150 }); + } catch (r) { + found = false; + } + expect(found).toEqual(false); +}); + +test('should reattach a markdown code cell when scrolling back into the viewport', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + + const h = await page.notebook.getNotebookInPanel(); + const mdCellSelector = '.jp-MarkdownCell[data-windowed-list-index="2"]'; + const mdCell = await h!.waitForSelector(mdCellSelector); + + const bbox = await h!.boundingBox(); + await page.mouse.move(bbox!.x, bbox!.y); + await Promise.all([ + mdCell.waitForElementState('hidden'), + h!.waitForSelector('.jp-MarkdownCell[data-windowed-list-index="6"]'), + page.mouse.wheel(0, 1200) + ]); + + await page.waitForTimeout(400); + + await page.mouse.wheel(0, -1200); + + expect(await h!.waitForSelector(mdCellSelector)).toBeDefined(); +}); + +test('should remove all cells including hidden outputs artifacts', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + + const h = await page.notebook.getNotebookInPanel(); + + const bbox = await h!.boundingBox(); + await page.mouse.move(bbox!.x, bbox!.y); + await Promise.all([ + h!.waitForSelector('.jp-MarkdownCell[data-windowed-list-index="6"]'), + page.mouse.wheel(0, 1200) + ]); + + // Select all cells + await page.keyboard.press('Control+a'); + // Delete all cells + await page.keyboard.press('d'); + await page.keyboard.press('d'); + + // Check that the notebook only contains one cell + expect(await (await h!.$('.jp-WindowedPanel-inner'))!.textContent()).toEqual( + '[ ]:' + ); + + // Check there are no hidden cells + let found = true; + try { + await h!.waitForSelector('.jp-Cell', { state: 'hidden', timeout: 150 }); + } catch (r) { + found = false; + } + expect(found).toEqual(false); +}); + +test('should scroll past end when running and inserting a cell at the viewport bottom', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + + const h = await page.notebook.getNotebookInPanel(); + const mdCellSelector = '.jp-MarkdownCell[data-windowed-list-index="2"]'; + const mdCell = await h!.waitForSelector(mdCellSelector); + + await page + .locator('.jp-Notebook-ExecutionIndicator[data-status="idle"]') + .waitFor(); + + await mdCell.click(); + + await expect + .soft( + page + .getByRole('main') + .locator('.jp-RawCell[data-windowed-list-index="4"]') + ) + .not.toBeInViewport(); + + await page.keyboard.press('Shift+Enter'); + + await expect( + page.getByRole('main').locator('.jp-RawCell[data-windowed-list-index="4"]') + ).toBeInViewport(); +}); + +test('should rendered injected styles of out-of-viewport cells', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${injectionFile}`); + await page.notebook.trust(); + + // Check the cell is out of the viewport + await expect + .soft(page.locator('.jp-Cell[data-windowed-list-index="4"]')) + .not.toBeVisible(); + + await page.waitForFunction(() => { + const cell = document.querySelector('.jp-Notebook-cell'); + if (cell) { + return ( + window.getComputedStyle(cell, '::after').content == + '"CSS ::after element"' + ); + } else { + return false; + } + }); + + const afterCellCount = await page.evaluate(() => { + let count = 0; + for (const cell of document.querySelectorAll('.jp-Notebook-cell')) { + count += + window.getComputedStyle(cell, '::after').content == + '"CSS ::after element"' + ? 1 + : 0; + } + return count; + }); + + expect(afterCellCount).toBeGreaterThan(1); +}); + +test('should rendered injected HTML scripts of out-of-viewport cells', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${injectionFile}`); + await page.notebook.trust(); + + // Check the cell is out of the viewport + await expect + .soft(page.locator('.jp-Cell[data-windowed-list-index="4"]')) + .not.toBeVisible(); + + await page.getByText('JavaScript injected from HTML').first().waitFor(); + expect( + await page.getByText('JavaScript injected from HTML').count() + ).toBeGreaterThan(1); +}); + +test('should rendered injected JavaScript snippets of out-of-viewport cells', async ({ + page, + tmpPath +}) => { + await page.notebook.openByPath(`${tmpPath}/${injectionFile}`); + await page.notebook.trust(); + + // Check the cell is out of the viewport + await expect + .soft(page.locator('.jp-Cell[data-windowed-list-index="4"]')) + .not.toBeVisible(); + + await page.getByText('JavaScript injected header').first().waitFor(); + expect( + await page.getByText('JavaScript injected header').count() + ).toBeGreaterThan(1); +}); diff --git a/galata/test/jupyterlab/workspace.test.ts b/galata/test/jupyterlab/workspace.test.ts index 9e2bf6b5d98a..9f8a2e9a9b32 100644 --- a/galata/test/jupyterlab/workspace.test.ts +++ b/galata/test/jupyterlab/workspace.test.ts @@ -22,8 +22,8 @@ test.use({ }); test.describe('Workspace', () => { - test.beforeAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); + test.beforeAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.uploadFile( path.resolve(__dirname, `./notebooks/${nbFile}`), `${tmpPath}/${nbFile}` @@ -34,8 +34,8 @@ test.describe('Workspace', () => { ); }); - test.afterAll(async ({ baseURL, request, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL, undefined, request); + test.afterAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.deleteDirectory(tmpPath); }); @@ -231,8 +231,8 @@ test.describe('Workspace', () => { }); test.describe('Workspace in doc mode', () => { - test.beforeAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.beforeAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.uploadFile( path.resolve(__dirname, `./notebooks/${nbFile}`), `${tmpPath}/${nbFile}` @@ -243,8 +243,8 @@ test.describe('Workspace in doc mode', () => { ); }); - test.afterAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.afterAll(async ({ request, tmpPath }) => { + const contents = galata.newContentsHelper(request); await contents.deleteDirectory(tmpPath); }); diff --git a/galata/test/jupyterlab/workspace.test.ts-snapshots/workspace-reset-jupyterlab-linux.png b/galata/test/jupyterlab/workspace.test.ts-snapshots/workspace-reset-jupyterlab-linux.png index 9e989961fada..ea98d8da985a 100644 Binary files a/galata/test/jupyterlab/workspace.test.ts-snapshots/workspace-reset-jupyterlab-linux.png and b/galata/test/jupyterlab/workspace.test.ts-snapshots/workspace-reset-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/workspace.test.ts-snapshots/workspace-simple-reset-jupyterlab-linux.png b/galata/test/jupyterlab/workspace.test.ts-snapshots/workspace-simple-reset-jupyterlab-linux.png index 9e989961fada..ea98d8da985a 100644 Binary files a/galata/test/jupyterlab/workspace.test.ts-snapshots/workspace-simple-reset-jupyterlab-linux.png and b/galata/test/jupyterlab/workspace.test.ts-snapshots/workspace-simple-reset-jupyterlab-linux.png differ diff --git a/galata/tsconfig.json b/galata/tsconfig.json index ddeea3b0be89..f3293fc0d08b 100644 --- a/galata/tsconfig.json +++ b/galata/tsconfig.json @@ -5,7 +5,8 @@ "outDir": "lib", "rootDir": "src", "module": "commonjs", - "types": ["node"] + "types": ["node"], + "lib": ["DOM", "DOM.iterable", "es2019.array"] }, "include": ["src/**/*"], "references": [ @@ -13,11 +14,14 @@ "path": "../packages/application" }, { - "path": "../packages/cells" + "path": "../packages/apputils" }, { "path": "../packages/coreutils" }, + { + "path": "../packages/debugger" + }, { "path": "../packages/docmanager" }, diff --git a/galata/update_snapshots.py b/galata/update_snapshots.py index 1f204744fec0..12d39bb21005 100644 --- a/galata/update_snapshots.py +++ b/galata/update_snapshots.py @@ -11,10 +11,11 @@ parser.add_argument("report", help="Path to the galata-report directory") args = parser.parse_args() -# Calculate hashes of all png files in the test/directory + def sha1(path): + """Calculate hashes of all png files in the test/directory""" with open(path, "rb") as f: - return hashlib.sha1(f.read()).hexdigest() + return hashlib.sha1(f.read()).hexdigest() # noqa: S324 filehashes = {sha1(p): p for p in Path(".").glob("**/*-snapshots/*-linux.png")} diff --git a/jupyterlab.desktop b/jupyterlab.desktop new file mode 100644 index 000000000000..93fe9409aa55 --- /dev/null +++ b/jupyterlab.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Name=JupyterLab +Comment=Run JupyterLab +Exec=jupyter-lab %f +Terminal=true +Type=Application +Icon=jupyterlab +StartupNotify=true +MimeType=application/x-ipynb+json; +Categories=Development;Education; +Keywords=python; diff --git a/jupyterlab.svg b/jupyterlab.svg new file mode 100644 index 000000000000..3e25e74c4c4f --- /dev/null +++ b/jupyterlab.svg @@ -0,0 +1,164 @@ + + + + logo-5.svg + Created using Figma 0.90 + + + + + + + + + + + + + + logo-5.svg + + + + diff --git a/jupyterlab/__init__.py b/jupyterlab/__init__.py index c97960a17cf6..e126187df18d 100644 --- a/jupyterlab/__init__.py +++ b/jupyterlab/__init__.py @@ -4,12 +4,12 @@ # Distributed under the terms of the Modified BSD License. from ._version import __version__ # noqa -from .handlers.announcements import ( # noqa - CheckForUpdate, - CheckForUpdateABC, - NeverCheckForUpdate, -) from .serverextension import load_jupyter_server_extension # noqa +from .handlers.announcements import ( + CheckForUpdate, # noqa + CheckForUpdateABC, # noqa + NeverCheckForUpdate, # noqa +) def _jupyter_server_extension_paths(): diff --git a/jupyterlab/__main__.py b/jupyterlab/__main__.py index b4c8ce70956d..2f15f7c517aa 100644 --- a/jupyterlab/__main__.py +++ b/jupyterlab/__main__.py @@ -1,3 +1,6 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + import sys from jupyterlab.labapp import main diff --git a/jupyterlab/_version.py b/jupyterlab/_version.py index 863aeb55d772..9816eb76c289 100644 --- a/jupyterlab/_version.py +++ b/jupyterlab/_version.py @@ -6,7 +6,7 @@ VersionInfo = namedtuple("VersionInfo", ["major", "minor", "micro", "releaselevel", "serial"]) # DO NOT EDIT THIS DIRECTLY! It is managed by bumpversion -version_info = VersionInfo(3, 6, 6, "final", 0) +version_info = VersionInfo(4, 0, 8, "final", 0) _specifier_ = {"alpha": "a", "beta": "b", "candidate": "rc", "final": ""} diff --git a/jupyterlab/browser-test.js b/jupyterlab/browser-test.js index c2f1658b59f4..f5905a2c4850 100644 --- a/jupyterlab/browser-test.js +++ b/jupyterlab/browser-test.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const playwright = require('playwright'); const path = require('path'); const fs = require('fs'); diff --git a/jupyterlab/browser_check.py b/jupyterlab/browser_check.py index 2f52d32d5018..4d86deeaa5ea 100644 --- a/jupyterlab/browser_check.py +++ b/jupyterlab/browser_check.py @@ -1,4 +1,6 @@ -# -*- coding: utf-8 -*- +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + """ This module is meant to run JupyterLab in a headless browser, making sure the application launches and starts up without errors. @@ -19,7 +21,7 @@ from tornado.ioloop import IOLoop from tornado.iostream import StreamClosedError from tornado.websocket import WebSocketClosedError -from traitlets import Bool +from traitlets import Bool, Unicode from .labapp import LabApp, get_app_dir from .tests.test_app import TestEnv @@ -41,14 +43,14 @@ def __init__(self): super().__init__(level=logging.ERROR) self.errored = False - def filter(self, record): + def filter(self, record): # noqa # Handle known StreamClosedError from Tornado # These occur when we forcibly close Websockets or # browser connections during the test. # https://github.com/tornadoweb/tornado/issues/2834 if ( hasattr(record, "exc_info") - and not record.exc_info is None + and record.exc_info is not None and isinstance(record.exc_info[1], (StreamClosedError, WebSocketClosedError)) ): return @@ -142,8 +144,8 @@ async def run_browser(url): if not osp.exists(osp.join(target, "node_modules")): if not osp.exists(target): os.makedirs(osp.join(target)) - await run_async_process(["jlpm", "init", "-y"], cwd=target) - await run_async_process(["jlpm", "add", "playwright@^1.9.2"], cwd=target) + await run_async_process(["npm", "init", "-y"], cwd=target) + await run_async_process(["npm", "install", "playwright@^1.9.2"], cwd=target) await run_async_process(["npx", "playwright", "install"], cwd=target) shutil.copy(osp.join(here, "browser-test.js"), osp.join(target, "browser-test.js")) await run_async_process(["node", "browser-test.js", url], cwd=target) @@ -154,11 +156,11 @@ def run_browser_sync(url): target = osp.join(get_app_dir(), "browser_test") if not osp.exists(osp.join(target, "node_modules")): os.makedirs(target) - subprocess.call(["jlpm", "init", "-y"], cwd=target) - subprocess.call(["jlpm", "add", "playwright@^1.9.2"], cwd=target) - subprocess.call(["npx", "playwright", "install"], cwd=target) + subprocess.call(["npm", "init", "-y"], cwd=target) # noqa S603 S607 + subprocess.call(["npm", "install", "playwright@^1.9.2"], cwd=target) # noqa S603 S607 + subprocess.call(["npx", "playwright", "install"], cwd=target) # noqa S603 S607 shutil.copy(osp.join(here, "browser-test.js"), osp.join(target, "browser-test.js")) - return subprocess.check_call(["node", "browser-test.js", url], cwd=target) + return subprocess.check_call(["node", "browser-test.js", url], cwd=target) # noqa S603 S607 class BrowserApp(LabApp): @@ -170,14 +172,14 @@ class BrowserApp(LabApp): open_browser = False serverapp_config = {"base_url": "/foo/"} - default_url = "/lab?reset" + default_url = Unicode("/lab?reset", config=True, help="The default URL to redirect to from `/`") ip = "127.0.0.1" flags = test_flags aliases = test_aliases test_browser = Bool(True) def initialize_settings(self): - self.settings.setdefault("page_config_data", dict()) + self.settings.setdefault("page_config_data", {}) self.settings["page_config_data"]["browserTest"] = True self.settings["page_config_data"]["buildAvailable"] = False self.settings["page_config_data"]["exposeAppInBrowser"] = True @@ -195,18 +197,6 @@ def _jupyter_server_extension_points(): return [{"module": __name__, "app": BrowserApp}] -# TODO: remove handling of --notebook arg and the following two -# functions in JupyterLab 4.0 -def load_jupyter_server_extension(serverapp): - serverapp.log.info("Loading BrowserApp as a classic notebook (v6) extension.") - extension = BrowserApp() - extension.serverapp = serverapp - extension.load_config_file() - extension.update_config(serverapp.config) - extension.parse_command_line(serverapp.extra_args) - extension.initialize() - - def _jupyter_server_extension_paths(): return [{"module": "jupyterlab.browser_check"}] @@ -218,13 +208,4 @@ def _jupyter_server_extension_paths(): BrowserApp.test_browser = False sys.argv.remove(option) - if "--notebook" in sys.argv: - from notebook.notebookapp import NotebookApp - - NotebookApp.default_url = "/lab" - sys.argv.remove("--notebook") - NotebookApp.nbserver_extensions = {"jupyterlab.browser_check": True} - NotebookApp.open_browser = False - NotebookApp.launch_instance() - else: - BrowserApp.launch_instance() + BrowserApp.launch_instance() diff --git a/jupyterlab/commands.py b/jupyterlab/commands.py index 8630ea4ef19c..c762299fea49 100644 --- a/jupyterlab/commands.py +++ b/jupyterlab/commands.py @@ -1,4 +1,3 @@ -# coding: utf-8 """JupyterLab command handler""" # Copyright (c) Jupyter Development Team. @@ -18,7 +17,6 @@ import subprocess import sys import tarfile -import warnings from copy import deepcopy from glob import glob from pathlib import Path @@ -28,14 +26,8 @@ from urllib.request import Request, quote, urljoin, urlopen from jupyter_core.paths import jupyter_config_dir -from jupyter_server.extension.serverextension import ( - GREEN_ENABLED, - GREEN_OK, - RED_DISABLED, - RED_X, -) +from jupyter_server.extension.serverextension import GREEN_ENABLED, GREEN_OK, RED_DISABLED, RED_X from jupyterlab_server.config import ( - LabConfig, get_federated_extensions, get_package_url, get_page_config, @@ -44,7 +36,7 @@ ) from jupyterlab_server.process import Process, WatchHelper, list2cmdline, which from packaging.version import Version -from traitlets import Bool, Dict, HasTraits, Instance, List, Unicode, default +from traitlets import Bool, HasTraits, Instance, List, Unicode, default from jupyterlab._version import __version__ from jupyterlab.coreconfig import CoreConfig @@ -89,15 +81,17 @@ def __init__(self, cmd, logger=None, cwd=None, kill_event=None, env=None): The environment for the process. """ if not isinstance(cmd, (list, tuple)): - raise ValueError("Command must be given as a list") + msg = "Command must be given as a list" + raise ValueError(msg) if kill_event and kill_event.is_set(): - raise ValueError("Process aborted") + msg = "Process aborted" + raise ValueError(msg) self.logger = _ensure_logger(logger) self._last_line = "" self.cmd = cmd - self.logger.debug("> " + list2cmdline(cmd)) + self.logger.debug(f"> {list2cmdline(cmd)}") self.proc = self._create_process( cwd=cwd, @@ -122,7 +116,8 @@ def wait(self): sys.stdout.write("\b") if kill_event.is_set(): self.terminate() - raise ValueError("Process was aborted") + msg = "Process was aborted" + raise ValueError(msg) try: out, _ = proc.communicate(timeout=0.1) cache.append(out) @@ -194,7 +189,15 @@ def dedupe_yarn(path, logger=None): """ had_dupes = ( ProgressProcess( - ["node", YARN_PATH, "yarn-deduplicate", "-s", "fewer", "--fail"], + [ + "node", + YARN_PATH, + "dlx", + "yarn-berry-deduplicate", + "-s", + "fewerHighest", + "--fail", + ], cwd=path, logger=logger, ).wait() @@ -213,7 +216,7 @@ def ensure_node_modules(cwd, logger=None): """ logger = _ensure_logger(logger) yarn_proc = ProgressProcess( - ["node", YARN_PATH, "check", "--verify-tree"], cwd=cwd, logger=logger + ["node", YARN_PATH, "--immutable", "--immutable-cache"], cwd=cwd, logger=logger ) ret = yarn_proc.wait() @@ -315,7 +318,7 @@ def watch_dev(logger=None): startup_regex=WEBPACK_EXPECT, ) - return package_procs + [wp_proc] + return [*package_procs, wp_proc] class AppOptions(HasTraits): @@ -331,13 +334,13 @@ def __init__(self, logger=None, core_config=None, **kwargs): if "app_dir" in kwargs and not kwargs["app_dir"]: kwargs.pop("app_dir") - super(AppOptions, self).__init__(**kwargs) + super().__init__(**kwargs) app_dir = Unicode(help="The application directory") use_sys_dir = Bool( True, - help=("Whether to shadow the default app_dir if that is set to a " "non-default value"), + help=("Whether to shadow the default app_dir if that is set to a non-default value"), ) logger = Instance(logging.Logger, help="The logger to use") @@ -408,10 +411,7 @@ def watch(app_options=None): _node_check(app_options.logger) handler = _AppHandler(app_options) - if app_options.splice_source: - package_procs = watch_packages(app_options.logger) - else: - package_procs = [] + package_procs = watch_packages(app_options.logger) if app_options.splice_source else [] return package_procs + handler.watch() @@ -459,22 +459,23 @@ def update_extension(name=None, all_=False, app_dir=None, app_options=None): def clean(app_options=None): """Clean the JupyterLab application directory.""" app_options = _ensure_options(app_options) - handler = _AppHandler(app_options) logger = app_options.logger app_dir = app_options.app_dir logger.info("Cleaning %s...", app_dir) if app_dir == pjoin(HERE, "dev"): - raise ValueError("Cannot clean the dev app") + msg = "Cannot clean the dev app" + raise ValueError(msg) if app_dir == pjoin(HERE, "core"): - raise ValueError("Cannot clean the core app") + msg = "Cannot clean the core app" + raise ValueError(msg) if getattr(app_options, "all", False): logger.info("Removing everything in %s...", app_dir) _rmtree_star(app_dir, logger) else: - possibleTargets = ["extensions", "settings", "staging", "static"] - targets = [t for t in possibleTargets if getattr(app_options, t)] + possible_targets = ["extensions", "settings", "staging", "static"] + targets = [t for t in possible_targets if getattr(app_options, t)] for name in targets: target = pjoin(app_dir, name) @@ -606,7 +607,7 @@ def read_package(target): # ---------------------------------------------------------------------- -class _AppHandler(object): +class _AppHandler: def __init__(self, options): """Create a new _AppHandler object""" options = _ensure_options(options) @@ -658,7 +659,7 @@ def install_extension(self, extension, existing=None, pin=None): # Local directories get name mangled and stored in metadata. if info["is_dir"]: config = self._read_build_config() - local = config.setdefault("local_extensions", dict()) + local = config.setdefault("local_extensions", {}) local[name] = info["source"] self._write_build_config(config) @@ -706,7 +707,7 @@ def build( staging = pjoin(app_dir, "staging") # Make sure packages are installed. - ret = self._run(["node", YARN_PATH, "install", "--non-interactive"], cwd=staging) + ret = self._run(["node", YARN_PATH, "install"], cwd=staging) if ret != 0: msg = "npm dependencies failed to install" self.logger.debug(msg) @@ -741,7 +742,7 @@ def watch(self): ) return [proc] - def list_extensions(self): + def list_extensions(self): # noqa """Print an output of the extensions.""" self._ensure_disabled_info() logger = self.logger @@ -764,14 +765,14 @@ def list_extensions(self): if local: logger.info("\n local extensions:") for name in sorted(local): - logger.info(" %s: %s" % (name, local[name])) + logger.info(f" {name}: {local[name]}") linked_packages = info["linked_packages"] if linked_packages: logger.info("\n linked packages:") for key in sorted(linked_packages): source = linked_packages[key]["source"] - logger.info(" %s: %s" % (key, source)) + logger.info(f" {key}: {source}") uninstalled_core = info["uninstalled_core"] if uninstalled_core: @@ -790,7 +791,7 @@ def list_extensions(self): for item in sorted(disabled): # Show that all plugins will be disabled if the whole extension matches if item in all_exts: - item += " (all plugins)" + item += " (all plugins)" # noqa PLW2901 logger.info(" %s" % item) # Here check if modules are improperly shadowed @@ -812,7 +813,7 @@ def list_extensions(self): logger.info("\nBuild recommended, please run `jupyter lab build`:") [logger.info(" %s" % item) for item in messages] - def build_check(self, fast=None): + def build_check(self, fast=None): # noqa """Determine whether JupyterLab should be built. Returns a list of messages. @@ -831,7 +832,7 @@ def build_check(self, fast=None): static_data = self.info["static_data"] old_jlab = static_data["jupyterlab"] - old_deps = static_data.get("dependencies", dict()) + old_deps = static_data.get("dependencies", {}) # Look for mismatched version. static_version = old_jlab.get("version", "") @@ -846,7 +847,7 @@ def build_check(self, fast=None): # Look for mismatched extensions. new_package = self._get_package_template(silent=fast) new_jlab = new_package["jupyterlab"] - new_deps = new_package.get("dependencies", dict()) + new_deps = new_package.get("dependencies", {}) for ext_type in ["extensions", "mimeExtensions"]: # Extensions that were added. @@ -865,7 +866,7 @@ def build_check(self, fast=None): # Look for mismatched dependencies src_pkg_dir = pjoin(REPO_ROOT, "packages") - for (pkg, dep) in new_deps.items(): + for pkg, dep in new_deps.items(): if old_deps.get(pkg, "").startswith(src_pkg_dir): continue if pkg not in old_deps: @@ -878,7 +879,7 @@ def build_check(self, fast=None): messages.append(msg % (pkg, old_deps[pkg], new_deps[pkg])) # Look for updated local extensions. - for (name, source) in local.items(): + for name, source in local.items(): if fast or name in shadowed_exts: continue dname = pjoin(app_dir, "extensions") @@ -886,7 +887,7 @@ def build_check(self, fast=None): messages.append("%s content changed" % name) # Look for updated linked packages. - for (name, item) in linked.items(): + for name, item in linked.items(): if fast or name in shadowed_exts: continue dname = pjoin(app_dir, "staging", "linked_packages") @@ -906,7 +907,7 @@ def uninstall_extension(self, name): if name in info["federated_extensions"]: if ( info["federated_extensions"][name] - .get("install", dict()) + .get("install", {}) .get("uninstallInstructions", None) ): logger.error( @@ -934,21 +935,21 @@ def uninstall_extension(self, name): local = info["local_extensions"] - for (extname, data) in info["extensions"].items(): + for extname, data in info["extensions"].items(): path = data["path"] if extname == name: - msg = "Uninstalling %s from %s" % (name, osp.dirname(path)) + msg = f"Uninstalling {name} from {osp.dirname(path)}" logger.info(msg) os.remove(path) # Handle local extensions. if extname in local: config = self._read_build_config() - data = config.setdefault("local_extensions", dict()) + data = config.setdefault("local_extensions", {}) # noqa PLW2901 del data[extname] self._write_build_config(config) return True - logger.warn('No labextension named "%s" installed' % name) + logger.warning('No labextension named "%s" installed' % name) return False def uninstall_all_extensions(self): @@ -957,7 +958,7 @@ def uninstall_all_extensions(self): Returns `True` if a rebuild is recommended, `False` otherwise """ should_rebuild = False - for (extname, _) in self.info["extensions"].items(): + for extname, _ in self.info["extensions"].items(): uninstalled = self.uninstall_extension(extname) should_rebuild = should_rebuild or uninstalled return should_rebuild @@ -968,7 +969,7 @@ def update_all_extensions(self): Returns `True` if a rebuild is recommended, `False` otherwise. """ should_rebuild = False - for (extname, _) in self.info["extensions"].items(): + for extname, _ in self.info["extensions"].items(): if extname in self.info["local_extensions"]: continue updated = self._update_extension(extname) @@ -993,20 +994,20 @@ def _update_extension(self, name): """ data = self.info["extensions"][name] if data["alias_package_source"]: - self.logger.warn("Skipping updating pinned extension '%s'." % name) + self.logger.warning("Skipping updating pinned extension '%s'." % name) return False try: latest = self._latest_compatible_package_version(name) except URLError: return False if latest is None: - self.logger.warn("No compatible version found for %s!" % (name,)) + self.logger.warning(f"No compatible version found for {name}!") return False if latest == data["version"]: self.logger.info("Extension %r already up to date" % name) return False - self.logger.info("Updating %s to version %s" % (name, latest)) - return self.install_extension("%s@%s" % (name, latest)) + self.logger.info(f"Updating {name} to version {latest}") + return self.install_extension(f"{name}@{latest}") def link_package(self, path): """Link a package at the given path. @@ -1033,7 +1034,7 @@ def link_package(self, path): # Add to metadata. config = self._read_build_config() - linked = config.setdefault("linked_packages", dict()) + linked = config.setdefault("linked_packages", {}) linked[info["name"]] = info["source"] self._write_build_config(config) @@ -1048,19 +1049,19 @@ def unlink_package(self, path): """ path = _normalize_path(path) config = self._read_build_config() - linked = config.setdefault("linked_packages", dict()) + linked = config.setdefault("linked_packages", {}) found = None - for (name, source) in linked.items(): - if name == path or source == path: + for name, source in linked.items(): + if path in {name, source}: found = name if found: del linked[found] else: - local = config.setdefault("local_extensions", dict()) - for (name, source) in local.items(): - if name == path or source == path: + local = config.setdefault("local_extensions", {}) + for name, source in local.items(): + if path in {name, source}: found = name if found: del local[found] @@ -1078,7 +1079,6 @@ def toggle_extension(self, extension, value, level="sys_prefix"): Returns `True` if a rebuild is recommended, `False` otherwise. """ - lab_config = LabConfig() app_settings_dir = osp.join(self.app_dir, "settings") page_config = get_static_page_config( @@ -1109,7 +1109,7 @@ def check_extension(self, extension, check_installed_only=False): return self._check_core_extension(extension, info, check_installed_only) if extension in info["linked_packages"]: - self.logger.info("%s:%s" % (extension, GREEN_ENABLED)) + self.logger.info(f"{extension}:{GREEN_ENABLED}") return True return self._check_common_extension(extension, info, check_installed_only) @@ -1117,43 +1117,43 @@ def check_extension(self, extension, check_installed_only=False): def _check_core_extension(self, extension, info, check_installed_only): """Check if a core extension is enabled or disabled""" if extension in info["uninstalled_core"]: - self.logger.info("%s:%s" % (extension, RED_X)) + self.logger.info(f"{extension}:{RED_X}") return False if check_installed_only: - self.logger.info("%s: %s" % (extension, GREEN_OK)) + self.logger.info(f"{extension}: {GREEN_OK}") return True if extension in info["disabled_core"]: - self.logger.info("%s: %s" % (extension, RED_DISABLED)) + self.logger.info(f"{extension}: {RED_DISABLED}") return False - self.logger.info("%s:%s" % (extension, GREEN_ENABLED)) + self.logger.info(f"{extension}:{GREEN_ENABLED}") return True def _check_common_extension(self, extension, info, check_installed_only): """Check if a common (non-core) extension is enabled or disabled""" if extension not in info["extensions"]: - self.logger.info("%s:%s" % (extension, RED_X)) + self.logger.info(f"{extension}:{RED_X}") return False errors = self._get_extension_compat()[extension] if errors: - self.logger.info("%s:%s (compatibility errors)" % (extension, RED_X)) + self.logger.info(f"{extension}:{RED_X} (compatibility errors)") return False if check_installed_only: - self.logger.info("%s: %s" % (extension, GREEN_OK)) + self.logger.info(f"{extension}: {GREEN_OK}") return True if _is_disabled(extension, info["disabled"]): - self.logger.info("%s: %s" % (extension, RED_DISABLED)) + self.logger.info(f"{extension}: {RED_DISABLED}") return False - self.logger.info("%s:%s" % (extension, GREEN_ENABLED)) + self.logger.info(f"{extension}:{GREEN_ENABLED}") return True def _get_app_info(self): """Get information about the app.""" - info = dict() + info = {} info["core_data"] = core_data = self.core_data info["extensions"] = extensions = self._get_extensions(core_data) @@ -1161,7 +1161,7 @@ def _get_app_info(self): info["linked_packages"] = self._get_linked_packages() info["app_extensions"] = app = [] info["sys_extensions"] = sys = [] - for (name, data) in extensions.items(): + for name, data in extensions.items(): data["is_local"] = name in info["local_extensions"] if data["location"] == "app": app.append(name) @@ -1213,7 +1213,7 @@ def _ensure_disabled_info(self): info["disabled_core"] = disabled_core - def _populate_staging(self, name=None, version=None, static_url=None, clean=False): + def _populate_staging(self, name=None, version=None, static_url=None, clean=False): # noqa """Set up the assets in the staging directory.""" app_dir = self.app_dir staging = pjoin(app_dir, "staging") @@ -1254,7 +1254,7 @@ def _populate_staging(self, name=None, version=None, static_url=None, clean=Fals target = pjoin(staging, fname) shutil.copy(pjoin(source_dir, fname), target) - for fname in [".yarnrc", "yarn.js"]: + for fname in [".yarnrc.yml", "yarn.js"]: target = pjoin(staging, fname) shutil.copy(pjoin(HERE, "staging", fname), target) @@ -1284,11 +1284,11 @@ def _populate_staging(self, name=None, version=None, static_url=None, clean=Fals # Update the local extensions. extensions = self.info["extensions"] removed = False - for (key, source) in self.info["local_extensions"].items(): + for key, source in self.info["local_extensions"].items(): # Handle a local extension that was removed. if key not in extensions: config = self._read_build_config() - data = config.setdefault("local_extensions", dict()) + data = config.setdefault("local_extensions", {}) del data[key] self._write_build_config(config) removed = True @@ -1302,7 +1302,7 @@ def _populate_staging(self, name=None, version=None, static_url=None, clean=Fals # Update the linked packages. linked = self.info["linked_packages"] - for (key, item) in linked.items(): + for key, item in linked.items(): dname = pjoin(staging, "linked_packages") self._update_local(key, item["source"], dname, item, "linked_packages") @@ -1350,19 +1350,11 @@ def _populate_staging(self, name=None, version=None, static_url=None, clean=Fals # copy known-good yarn.lock if missing lock_path = pjoin(staging, "yarn.lock") lock_template = pjoin(HERE, "staging", "yarn.lock") - if ( - self.registry != YARN_DEFAULT_REGISTRY - ): # Replace on the fly the yarn repository see #3658 - with open(lock_template, encoding="utf-8") as f: - template = f.read() - template = template.replace(YARN_DEFAULT_REGISTRY, self.registry.strip("/")) - with open(lock_path, "w", encoding="utf-8") as f: - f.write(template) - elif not osp.exists(lock_path): + if not osp.exists(lock_path): shutil.copy(lock_template, lock_path) os.chmod(lock_path, stat.S_IWRITE | stat.S_IREAD) - def _get_package_template(self, silent=False): + def _get_package_template(self, silent=False): # noqa """Get the template the for staging package.json file.""" logger = self.logger # make a deep copy of the data so we don't influence the core data @@ -1380,17 +1372,17 @@ def format_path(path): path = path.lower() return path - jlab["linkedPackages"] = dict() + jlab["linkedPackages"] = {} # Handle local extensions. - for (key, source) in local.items(): + for key, source in local.items(): if key in shadowed_exts: continue jlab["linkedPackages"][key] = source data["resolutions"][key] = "file:" + self.info["extensions"][key]["path"] # Handle linked packages. - for (key, item) in linked.items(): + for key, item in linked.items(): if key in shadowed_exts: continue path = pjoin(self.app_dir, "staging", "linked_packages") @@ -1399,11 +1391,11 @@ def format_path(path): jlab["linkedPackages"][key] = item["source"] data["resolutions"][key] = format_path(path) - data["jupyterlab"]["extensionMetadata"] = dict() + data["jupyterlab"]["extensionMetadata"] = {} # Handle extensions compat_errors = self._get_extension_compat() - for (key, value) in extensions.items(): + for key, value in extensions.items(): # Reject incompatible extensions with a message. errors = compat_errors[key] if errors: @@ -1479,7 +1471,7 @@ def _update_local(self, name, source, dname, data, dtype): def _get_extensions(self, core_data): """Get the extensions for the application.""" app_dir = self.app_dir - extensions = dict() + extensions = {} # Get system level packages. sys_path = pjoin(self.sys_dir, "extensions") @@ -1498,13 +1490,13 @@ def _get_extensions(self, core_data): def _get_extensions_in_dir(self, dname, core_data): """Get the extensions in a given directory.""" - extensions = dict() + extensions = {} location = "app" if dname == self.app_dir else "sys" for target in glob(pjoin(dname, "extensions", "*.tgz")): data = read_package(target) - deps = data.get("dependencies", dict()) + deps = data.get("dependencies", {}) name = data["name"] - jlab = data.get("jupyterlab", dict()) + jlab = data.get("jupyterlab", {}) path = osp.abspath(target) filename = osp.basename(target) @@ -1513,30 +1505,31 @@ def _get_extensions_in_dir(self, dname, core_data): else: alias = None url = get_package_url(data) - extensions[alias or name] = dict( - path=path, - filename=osp.basename(path), - url=url, - version=data["version"], + extensions[alias or name] = { + "description": data.get("description", ""), + "path": path, + "filename": osp.basename(path), + "url": url, + "version": data["version"], # Only save the package name if the extension name is an alias - alias_package_source=name if alias else None, - jupyterlab=jlab, - dependencies=deps, - tar_dir=osp.dirname(path), - location=location, - ) + "alias_package_source": name if alias else None, + "jupyterlab": jlab, + "dependencies": deps, + "tar_dir": osp.dirname(path), + "location": location, + } return extensions def _get_extension_compat(self): """Get the extension compatibility info.""" - compat = dict() + compat = {} core_data = self.info["core_data"] seen = set() - for (name, data) in self.info["federated_extensions"].items(): + for name, data in self.info["federated_extensions"].items(): deps = data["dependencies"] compat[name] = _validate_compatibility(name, deps, core_data) seen.add(name) - for (name, data) in self.info["extensions"].items(): + for name, data in self.info["extensions"].items(): if name in seen: continue deps = data["dependencies"] @@ -1551,18 +1544,18 @@ def _get_linked_packages(self): """Get the linked packages.""" info = self._get_local_data("linked_packages") dname = pjoin(self.app_dir, "staging", "linked_packages") - for (name, source) in info.items(): - info[name] = dict(source=source, filename="", tar_dir=dname) + for name, source in info.items(): + info[name] = {"source": source, "filename": "", "tar_dir": dname} if not osp.exists(dname): return info for path in glob(pjoin(dname, "*.tgz")): - path = osp.abspath(path) + path = osp.abspath(path) # noqa PLW2901 data = read_package(path) name = data["name"] if name not in info: - self.logger.warn("Removing orphaned linked package %s" % name) + self.logger.warning("Removing orphaned linked package %s" % name) os.remove(path) continue item = info[name] @@ -1601,7 +1594,7 @@ def _list_extensions(self, info, ext_type): error_accumulator = {} - logger.info(" %s dir: %s" % (ext_type, dname)) + logger.info(f" {ext_type} dir: {dname}") for name in sorted(names): if name in info["federated_extensions"]: continue @@ -1622,9 +1615,9 @@ def _list_extensions(self, info, ext_type): # If we have the package name in the data, this means this extension's name is the alias name alias_package_source = data["alias_package_source"] if alias_package_source: - logger.info(" %s %s v%s%s" % (name, alias_package_source, version, extra)) + logger.info(f" {name} {alias_package_source} v{version}{extra}") else: - logger.info(" %s v%s%s" % (name, version, extra)) + logger.info(f" {name} v{version}{extra}") if errors: error_accumulator[name] = (version, errors) @@ -1641,7 +1634,7 @@ def _list_federated_extensions(self): error_accumulator = {} - ext_dirs = dict((p, False) for p in self.labextensions_path) + ext_dirs = {p: False for p in self.labextensions_path} for value in info["federated_extensions"].values(): ext_dirs[value["ext_dir"]] = True @@ -1669,8 +1662,8 @@ def _list_federated_extensions(self): install = data.get("install") if install: - extra += " (%s, %s)" % (install["packageManager"], install["packageName"]) - logger.info(" %s v%s%s" % (name, version, extra)) + extra += " ({}, {})".format(install["packageManager"], install["packageName"]) + logger.info(f" {name} v{version}{extra}") if errors: error_accumulator[name] = (version, errors) # Add a spacer line after @@ -1699,16 +1692,16 @@ def _get_local_data(self, source): """Get the local data for extensions or linked packages.""" config = self._read_build_config() - data = config.setdefault(source, dict()) + data = config.setdefault(source, {}) dead = [] - for (name, source) in data.items(): + for name, source in data.items(): if not osp.exists(source): dead.append(name) for name in dead: link_type = source.replace("_", " ") - msg = '**Note: Removing dead %s "%s"' % (link_type, name) - self.logger.warn(msg) + msg = f'**Note: Removing dead {link_type} "{name}"' + self.logger.warning(msg) del data[name] if dead: @@ -1737,12 +1730,12 @@ def _install_extension(self, extension, tempdir, pin=None): try: version = self._latest_compatible_package_version(name) except URLError: - raise ValueError(msg) + raise ValueError(msg) from None else: raise ValueError(msg) # Verify package compatibility. - deps = data.get("dependencies", dict()) + deps = data.get("dependencies", {}) errors = _validate_compatibility(extension, deps, self.core_data) if errors: msg = _format_compatibility_errors(data["name"], data["version"], errors) @@ -1751,13 +1744,13 @@ def _install_extension(self, extension, tempdir, pin=None): version = self._latest_compatible_package_version(name) except URLError: # We cannot add any additional information to error message - raise ValueError(msg) + raise ValueError(msg) from None if version and name: self.logger.debug("Incompatible extension:\n%s", name) self.logger.debug("Found compatible version: %s", version) with TemporaryDirectory() as tempdir2: - return self._install_extension("%s@%s" % (name, version), tempdir2) + return self._install_extension(f"{name}@{version}", tempdir2) # Extend message to better guide the user what to do: conflicts = "\n".join(msg.splitlines()[2:]) @@ -1786,7 +1779,7 @@ def _extract_package(self, source, tempdir, pin=None): if is_dir and not osp.exists(pjoin(source, "node_modules")): self._run(["node", YARN_PATH, "install"], cwd=source) - info = dict(source=source, is_dir=is_dir) + info = {"source": source, "is_dir": is_dir} ret = self._run([which("npm"), "pack", source], cwd=tempdir) if ret != 0: @@ -1804,7 +1797,7 @@ def _extract_package(self, source, tempdir, pin=None): info["path"] = path if pin: old_path = info["path"] - new_path = pjoin(osp.dirname(old_path), "{}{}.tgz".format(PIN_PREFIX, pin)) + new_path = pjoin(osp.dirname(old_path), f"{PIN_PREFIX}{pin}.tgz") shutil.move(old_path, new_path) info["path"] = new_path @@ -1835,13 +1828,12 @@ def sort_key(key_value): # skip deprecated versions if "deprecated" in data: self.logger.debug( - "Disregarding compatible version of package as it is deprecated: %s@%s" - % (name, version) + f"Disregarding compatible version of package as it is deprecated: {name}@{version}" ) continue # Verify that the version is a valid extension. with TemporaryDirectory() as tempdir: - info = self._extract_package("%s@%s" % (name, version), tempdir) + info = self._extract_package(f"{name}@{version}", tempdir) if _validate_extension(info["data"]): # Invalid, do not consider other versions return @@ -1869,7 +1861,6 @@ def sort_key(key_value): return _semver_key(key_value[0], prerelease_first=True) for version, data in sorted(versions.items(), key=sort_key, reverse=True): - # skip deprecated versions if "deprecated" in data: continue @@ -1878,14 +1869,14 @@ def sort_key(key_value): errors = _validate_compatibility(name, deps, core_data) if not errors: # Found a compatible version - keys.append("%s@%s" % (name, version)) + keys.append(f"{name}@{version}") break # break inner for versions = {} if not keys: return versions with TemporaryDirectory() as tempdir: - ret = self._run([which("npm"), "pack"] + keys, cwd=tempdir) + ret = self._run([which("npm"), "pack", *keys], cwd=tempdir) if ret != 0: msg = '"%s" is not a valid npm package' raise ValueError(msg % keys) @@ -1925,7 +1916,7 @@ def sort_key(key_value): core_deps = core_data["resolutions"] singletons = core_data["jupyterlab"]["singletonPackages"] - for (key, value) in latest_deps.items(): + for key, value in latest_deps.items(): if key in singletons: # Drop prereleases in comparisons to allow extension authors # to not have to update their versions for each @@ -1962,7 +1953,8 @@ def _run(self, cmd, **kwargs): Returns the exit code. """ if self.kill_event.is_set(): - raise ValueError("Command was killed") + msg = "Command was killed" + raise ValueError(msg) kwargs["logger"] = self.logger kwargs["kill_event"] = self.kill_event @@ -1974,7 +1966,7 @@ def _node_check(logger): """Check for the existence of nodejs with the correct version.""" node = which("node") try: - output = subprocess.check_output([node, "node-version-check.js"], cwd=HERE) + output = subprocess.check_output([node, "node-version-check.js"], cwd=HERE) # noqa S603 logger.debug(output.decode("utf-8")) except Exception: data = CoreConfig()._data @@ -1983,7 +1975,7 @@ def _node_check(logger): "Please install nodejs %s before continuing. nodejs may be installed using conda or directly from the nodejs website." % ver ) - raise ValueError(msg) + raise ValueError(msg) from None def _yarn_config(logger): @@ -2002,7 +1994,7 @@ def _yarn_config(logger): try: output_binary = subprocess.check_output( - [node, YARN_PATH, "config", "list", "--json"], stderr=subprocess.PIPE, cwd=HERE + [node, YARN_PATH, "config", "--json"], stderr=subprocess.PIPE, cwd=HERE # noqa S603 ) output = output_binary.decode("utf-8") lines = iter(output.splitlines()) @@ -2024,9 +2016,9 @@ def _yarn_config(logger): ) ) except Exception as e: - logger.error("Fail to get yarn configuration. {!s}".format(e)) - finally: - return configuration + logger.error(f"Fail to get yarn configuration. {e!s}") + + return configuration def _ensure_logger(logger=None): @@ -2069,7 +2061,7 @@ def _rmtree_star(path, logger): _rmtree(file_path, logger) -def _validate_extension(data): +def _validate_extension(data): # noqa """Detect if a package is an extension using its metadata. Returns any problems it finds. @@ -2081,8 +2073,8 @@ def _validate_extension(data): return ["The `jupyterlab` key must be a JSON object"] extension = jlab.get("extension", False) mime_extension = jlab.get("mimeExtension", False) - themePath = jlab.get("themePath", "") - schemaDir = jlab.get("schemaDir", "") + theme_path = jlab.get("themePath", "") + schema_dir = jlab.get("schemaDir", "") messages = [] if not extension and not mime_extension: @@ -2113,11 +2105,11 @@ def _validate_extension(data): if mime_extension and mime_extension not in files: messages.append('Missing mimeExtension module "%s"' % mime_extension) - if themePath and not any(f.startswith(str(Path(themePath))) for f in files): - messages.append('themePath is empty: "%s"' % themePath) + if theme_path and not any(f.startswith(str(Path(theme_path))) for f in files): + messages.append('themePath is empty: "%s"' % theme_path) - if schemaDir and not any(f.startswith(str(Path(schemaDir))) for f in files): - messages.append('schemaDir is empty: "%s"' % schemaDir) + if schema_dir and not any(f.startswith(str(Path(schema_dir))) for f in files): + messages.append('schemaDir is empty: "%s"' % schema_dir) return messages @@ -2128,7 +2120,7 @@ def _tarsum(input_file): """ tar = tarfile.open(input_file, "r") chunk_size = 100 * 1024 - h = hashlib.new("sha1") + h = hashlib.new("sha1") # noqa: S324 for member in tar: if not member.isfile(): @@ -2158,7 +2150,7 @@ def _validate_compatibility(extension, deps, core_data): errors = [] - for (key, value) in deps.items(): + for key, value in deps.items(): if key in singletons: # Drop prereleases in comparisons to allow extension authors # to not have to update their versions for each @@ -2184,7 +2176,7 @@ def _test_overlap(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False): return cmp == 0 -def _compare_ranges(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False): +def _compare_ranges(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False): # noqa """Test whether two version specs overlap. Returns `None` if we cannot determine compatibility, @@ -2269,7 +2261,8 @@ def noop(x, y, z): return_value = None continue - raise AssertionError("Unexpected case comparing version ranges") + msg = "Unexpected case comparing version ranges" + raise AssertionError(msg) if return_value is False: return_value = None @@ -2281,7 +2274,7 @@ def _is_disabled(name, disabled=None): disabled = disabled or {} for pattern, value in disabled.items(): # skip packages explicitly marked as not disabled - if value == False: + if value is False: continue if name == pattern: return True @@ -2310,7 +2303,7 @@ def _format_compatibility_errors(name, version, errors): msg += "Extension".ljust(l1) msg += "Package\n" - for (pkg, jlab, ext) in msgs: + for pkg, jlab, ext in msgs: msg += jlab.ljust(l0) + ext.ljust(l1) + pkg + "\n" return msg @@ -2322,7 +2315,7 @@ def _log_multiple_compat_errors(logger, errors_map): outdated = [] others = [] - for name, (version, errors) in errors_map.items(): + for name, (_, errors) in errors_map.items(): age = _compat_error_age(errors) if age > 0: outdated.append(name) @@ -2330,7 +2323,7 @@ def _log_multiple_compat_errors(logger, errors_map): others.append(name) if outdated: - logger.warn( + logger.warning( "\n ".join( [ "\n The following extensions are outdated:", @@ -2343,7 +2336,7 @@ def _log_multiple_compat_errors(logger, errors_map): for name in others: version, errors = errors_map[name] msg = _format_compatibility_errors(name, version, errors) - logger.warn(msg + "\n") + logger.warning(f"{msg}\n") def _log_single_compat_errors(logger, name, version, errors): @@ -2351,14 +2344,14 @@ def _log_single_compat_errors(logger, name, version, errors): age = _compat_error_age(errors) if age > 0: - logger.warn('The extension "%s" is outdated.\n', name) + logger.warning('The extension "%s" is outdated.\n', name) else: msg = _format_compatibility_errors(name, version, errors) - logger.warn(msg + "\n") + logger.warning(f"{msg}\n") def _compat_error_age(errors): - """Compare all incompatabilites for an extension. + """Compare all incompatibilities for an extension. Returns a number > 0 if all extensions are older than that supported by lab. Returns a number < 0 if all extensions are newer than that supported by lab. @@ -2427,14 +2420,11 @@ def _semver_key(version, prerelease_first=False): (0.x -> 1.0-pre -> 1.x -> 2.0-pre -> 2.x). """ v = make_semver(version, True) - if prerelease_first: - key = (0,) if v.prerelease else (1,) - else: - key = () - key = key + (v.major, v.minor, v.patch) + key = ((0,) if v.prerelease else (1,)) if prerelease_first else () + key = (*key, v.major, v.minor, v.patch) if not prerelease_first: # NOT having a prerelease is > having one - key = key + (0,) if v.prerelease else (1,) + key = (*key, 0) if v.prerelease else (1,) if v.prerelease: key = key + tuple(_semver_prerelease_key(v.prerelease)) @@ -2446,9 +2436,7 @@ def _fetch_package_metadata(registry, name, logger): req = Request( urljoin(registry, quote(name, safe="@")), headers={ - "Accept": ( - "application/vnd.npm.install-v1+json;" " q=1.0, application/json; q=0.8, */*" - ) + "Accept": ("application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*") }, ) try: @@ -2456,7 +2444,7 @@ def _fetch_package_metadata(registry, name, logger): except AttributeError: logger.debug("Fetching URL: %s" % (req.get_full_url())) try: - with contextlib.closing(urlopen(req)) as response: + with contextlib.closing(urlopen(req)) as response: # noqa S310 return json.loads(response.read().decode("utf-8")) except URLError as exc: logger.warning("Failed to fetch package metadata for %r: %r", name, exc) diff --git a/jupyterlab/coreconfig.py b/jupyterlab/coreconfig.py index 8d9db27189cc..ac0dfa20c60c 100644 --- a/jupyterlab/coreconfig.py +++ b/jupyterlab/coreconfig.py @@ -1,4 +1,3 @@ -# coding: utf-8 # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. @@ -33,10 +32,11 @@ def _only_nonlab(collection): lumino and react). """ if isinstance(collection, dict): - return dict((k, v) for (k, v) in collection.items() if not _is_lab_package(k)) + return {k: v for (k, v) in collection.items() if not _is_lab_package(k)} elif isinstance(collection, (list, tuple)): return list(filterfalse(_is_lab_package, collection)) - raise TypeError("collection arg should be either dict or list/tuple") + msg = "collection arg should be either dict or list/tuple" + raise TypeError(msg) class CoreConfig: @@ -66,11 +66,14 @@ def add(self, name, semver, extension=False, mime_extension=False): """ data = self._data if not name: - raise ValueError("Missing package name") + msg = "Missing package name" + raise ValueError(msg) if not semver: - raise ValueError("Missing package semver") + msg = "Missing package semver" + raise ValueError(msg) if name in data["resolutions"]: - raise ValueError("Package already present: %r" % (name,)) + msg = f"Package already present: {name!r}" + raise ValueError(msg) data["resolutions"][name] = semver # If both mimeExtension and extensions are True, treat @@ -131,23 +134,21 @@ def clear_packages(self, lab_only=True): def extensions(self): """A dict mapping all extension names to their semver""" data = self._data - return dict((k, data["resolutions"][k]) for k in data["jupyterlab"]["extensions"].keys()) + return {k: data["resolutions"][k] for k in data["jupyterlab"]["extensions"]} @property def mime_extensions(self): """A dict mapping all MIME extension names to their semver""" data = self._data - return dict( - (k, data["resolutions"][k]) for k in data["jupyterlab"]["mimeExtensions"].keys() - ) + return {k: data["resolutions"][k] for k in data["jupyterlab"]["mimeExtensions"]} @property def singletons(self): """A dict mapping all singleton names to their semver""" data = self._data - return dict( - (k, data["resolutions"].get(k, None)) for k in data["jupyterlab"]["singletonPackages"] - ) + return { + k: data["resolutions"].get(k, None) for k in data["jupyterlab"]["singletonPackages"] + } @property def static_dir(self): diff --git a/jupyterlab/debuglog.py b/jupyterlab/debuglog.py index 68d97deb41d5..ab5127865b33 100644 --- a/jupyterlab/debuglog.py +++ b/jupyterlab/debuglog.py @@ -1,4 +1,3 @@ -# coding: utf-8 """A mixin for adding a debug log file. """ @@ -12,6 +11,7 @@ import sys import tempfile import traceback +import warnings from traitlets import Unicode from traitlets.config import Configurable @@ -51,11 +51,11 @@ def debug_logging(self): for line in msg: self.log.debug(line) if isinstance(ex, SystemExit): - print("An error occurred. See the log file for details: ", log_path) + warnings.warn(f"An error occurred. See the log file for details: {log_path!s}") raise - print("An error occurred.") - print(msg[-1].strip()) - print("See the log file for details: ", log_path) + warnings.warn("An error occurred.") + warnings.warn(msg[-1].strip()) + warnings.warn(f"See the log file for details: {log_path!s}") self.exit(1) else: log.removeHandler(_debug_handler) diff --git a/jupyterlab/extensions/__init__.py b/jupyterlab/extensions/__init__.py new file mode 100644 index 000000000000..ba9d89f360c5 --- /dev/null +++ b/jupyterlab/extensions/__init__.py @@ -0,0 +1,46 @@ +"""Extension manager for JupyterLab.""" + +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +import sys +from typing import Optional + +from traitlets.config import Configurable + +from .manager import ActionResult, ExtensionManager, ExtensionPackage # noqa: F401 +from .pypi import PyPIExtensionManager +from .readonly import ReadOnlyExtensionManager + +# See compatibility note on `group` keyword in https://docs.python.org/3/library/importlib.metadata.html#entry-points +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points + +# Supported third-party services +MANAGERS = {} + +for entry in entry_points(group="jupyterlab.extension_manager_v1"): + MANAGERS[entry.name] = entry + + +# Entry points + + +def get_readonly_manager( + app_options: Optional[dict] = None, + ext_options: Optional[dict] = None, + parent: Optional[Configurable] = None, +) -> ExtensionManager: + """Read-Only Extension Manager factory""" + return ReadOnlyExtensionManager(app_options, ext_options, parent) + + +def get_pypi_manager( + app_options: Optional[dict] = None, + ext_options: Optional[dict] = None, + parent: Optional[Configurable] = None, +) -> ExtensionManager: + """PyPi Extension Manager factory""" + return PyPIExtensionManager(app_options, ext_options, parent) diff --git a/jupyterlab/extensions/manager.py b/jupyterlab/extensions/manager.py new file mode 100644 index 000000000000..1e279de85c86 --- /dev/null +++ b/jupyterlab/extensions/manager.py @@ -0,0 +1,584 @@ +"""Base classes for the extension manager.""" + +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +import json +import re +from dataclasses import dataclass, field, replace +from pathlib import Path +from typing import Dict, List, Optional, Set, Tuple + +import tornado +from traitlets.config import Configurable, LoggingConfigurable + +from jupyterlab.commands import ( + _AppHandler, + _ensure_options, + disable_extension, + enable_extension, + get_app_info, +) + +PYTHON_TO_SEMVER = {"a": "-alpha.", "b": "-beta.", "rc": "-rc."} + + +def _ensure_compat_errors(info, app_options): + """Ensure that the app info has compat_errors field""" + handler = _AppHandler(app_options) + info["compat_errors"] = handler._get_extension_compat() + + +_message_map = { + "install": re.compile(r"(?P.*) needs to be included in build"), + "uninstall": re.compile(r"(?P.*) needs to be removed from build"), + "update": re.compile(r"(?P.*) changed from (?P.*) to (?P.*)"), +} + + +def _build_check_info(app_options): + """Get info about packages scheduled for (un)install/update""" + handler = _AppHandler(app_options) + messages = handler.build_check(fast=True) + # Decode the messages into a dict: + status = {"install": [], "uninstall": [], "update": []} + for msg in messages: + for key, pattern in _message_map.items(): + match = pattern.match(msg) + if match: + status[key].append(match.group("name")) + return status + + +@dataclass(frozen=True) +class ExtensionPackage: + """Extension package entry. + + Attributes: + name: Package name + description: Package description + homepage_url: Package home page + pkg_type: Type of package - ["prebuilt", "source"] + allowed: [optional] Whether this extension is allowed or not - default True + approved: [optional] Whether the package is approved by your administrators - default False + companion: [optional] Type of companion for the frontend extension - [None, "kernel", "server"]; default None + core: [optional] Whether the package is a core package or not - default False + enabled: [optional] Whether the package is enabled or not - default False + install: [optional] Extension package installation instructions - default None + installed: [optional] Whether the extension is currently installed - default None + installed_version: [optional] Installed version - default "" + latest_version: [optional] Latest available version - default "" + status: [optional] Package status - ["ok", "warning", "error"]; default "ok" + author: [optional] Package author - default None + license: [optional] Package license - default None + bug_tracker_url: [optional] Package bug tracker URL - default None + documentation_url: [optional] Package documentation URL - default None + package_manager_url: Package home page in the package manager - default None + repository_url: [optional] Package code repository URL - default None + """ + + name: str + description: str + homepage_url: str + pkg_type: str + allowed: bool = True + approved: bool = False + companion: Optional[str] = None + core: bool = False + enabled: bool = False + install: Optional[dict] = None + installed: Optional[bool] = None + installed_version: str = "" + latest_version: str = "" + status: str = "ok" + author: Optional[str] = None + license: Optional[str] = None # noqa + bug_tracker_url: Optional[str] = None + documentation_url: Optional[str] = None + package_manager_url: Optional[str] = None + repository_url: Optional[str] = None + + +@dataclass(frozen=True) +class ActionResult: + """Action result + + Attributes: + status: Action status - ["ok", "warning", "error"] + message: Action status explanation + needs_restart: Required action follow-up - Valid follow-up are "frontend", "kernel" and "server" + """ + + # Note: no simple way to use Enum in dataclass - https://stackoverflow.com/questions/72859557/typing-dataclass-that-can-only-take-enum-values + # keeping str for simplicity + status: str + message: Optional[str] = None + needs_restart: List[str] = field(default_factory=list) + + +@dataclass +class ExtensionManagerOptions: + """Extension manager options. + + Attributes: + allowed_extensions_uris: A list of comma-separated URIs to get the allowed extensions list + blocked_extensions_uris: A list of comma-separated URIs to get the blocked extensions list + listings_refresh_seconds: The interval delay in seconds to refresh the lists + listings_tornado_options: The optional kwargs to use for the listings HTTP requests as described on https://www.tornadoweb.org/en/stable/httpclient.html#tornado.httpclient.HTTPRequest + """ + + allowed_extensions_uris: Set[str] = field(default_factory=set) + blocked_extensions_uris: Set[str] = field(default_factory=set) + listings_refresh_seconds: int = 60 * 60 + listings_tornado_options: dict = field(default_factory=dict) + + +@dataclass(frozen=True) +class ExtensionManagerMetadata: + """Extension manager metadata. + + Attributes: + name: Extension manager name to be displayed + can_install: Whether the extension manager can un-/install packages (default False) + install_path: Installation path for the extensions (default None); e.g. environment path + """ + + name: str + can_install: bool = False + install_path: Optional[str] = None + + +@dataclass +class ExtensionsCache: + """Extensions cache + + Attributes: + cache: Extension list per page + last_page: Last available page result + """ + + cache: Dict[int, Optional[Dict[str, ExtensionPackage]]] = field(default_factory=dict) + last_page: int = 1 + + +class ExtensionManager(LoggingConfigurable): + """Base abstract extension manager. + + Note: + Any concrete implementation will need to implement the five + following abstract methods: + - :ref:`metadata` + - :ref:`get_latest_version` + - :ref:`list_packages` + - :ref:`install` + - :ref:`uninstall` + + It could be interesting to override the :ref:`get_normalized_name` + method too. + + Args: + app_options: Application options + ext_options: Extension manager options + parent: Configurable parent + + Attributes: + log: Logger + app_dir: Application directory + core_config: Core configuration + app_options: Application options + options: Extension manager options + """ + + def __init__( + self, + app_options: Optional[dict] = None, + ext_options: Optional[dict] = None, + parent: Optional[Configurable] = None, + ) -> None: + super().__init__(parent=parent) + app_options = _ensure_options(app_options) + self.log = app_options.logger + self.app_dir = Path(app_options.app_dir) + self.core_config = app_options.core_config + self.app_options = app_options + self.options = ExtensionManagerOptions(**(ext_options or {})) + self._extensions_cache: Dict[Optional[str], ExtensionsCache] = {} + self._listings_cache: Optional[dict] = None + self._listings_block_mode = True + self._listing_fetch: Optional[tornado.ioloop.PeriodicCallback] = None + + if len(self.options.allowed_extensions_uris) or len(self.options.blocked_extensions_uris): + self._listings_block_mode = len(self.options.allowed_extensions_uris) == 0 + if not self._listings_block_mode and len(self.options.blocked_extensions_uris) > 0: + self.log.warning( + "You have define simultaneously blocked and allowed extensions listings. The allowed listing will take precedence." + ) + + self._listing_fetch = tornado.ioloop.PeriodicCallback( + self._fetch_listings, + callback_time=self.options.listings_refresh_seconds * 1000, + jitter=0.1, + ) + self._listing_fetch.start() + + def __del__(self): + if self._listing_fetch is not None: + self._listing_fetch.stop() + + @property + def metadata(self) -> ExtensionManagerMetadata: + """Extension manager metadata.""" + raise NotImplementedError() + + async def get_latest_version(self, extension: str) -> Optional[str]: + """Return the latest available version for a given extension. + + Args: + pkg: The extension name + Returns: + The latest available version + """ + raise NotImplementedError() + + async def list_packages( + self, query: str, page: int, per_page: int + ) -> Tuple[Dict[str, ExtensionPackage], Optional[int]]: + """List the available extensions. + + Args: + query: The search extension query + page: The result page + per_page: The number of results per page + Returns: + The available extensions in a mapping {name: metadata} + The results last page; None if the manager does not support pagination + """ + raise NotImplementedError() + + async def install(self, extension: str, version: Optional[str] = None) -> ActionResult: + """Install the required extension. + + Note: + If the user must be notified with a message (like asking to restart the + server), the result should be + {"status": "warning", "message": ""} + + Args: + extension: The extension name + version: The version to install; default None (i.e. the latest possible) + Returns: + The action result + """ + raise NotImplementedError() + + async def uninstall(self, extension: str) -> ActionResult: + """Uninstall the required extension. + + Note: + If the user must be notified with a message (like asking to restart the + server), the result should be + {"status": "warning", "message": ""} + + Args: + extension: The extension name + Returns: + The action result + """ + raise NotImplementedError() + + async def disable(self, extension: str) -> ActionResult: + """Disable an extension. + + Args: + extension: The extension name + Returns: + The action result + """ + try: + disable_extension(extension, app_options=self.app_options) + return ActionResult(status="ok", needs_restart=["frontend"]) + except Exception as err: + return ActionResult(status="error", message=repr(err)) + + async def enable(self, extension: str) -> ActionResult: + """Enable an extension. + + Args: + extension: The extension name + Returns: + The action result + """ + try: + enable_extension(extension, app_options=self.app_options) + return ActionResult(status="ok", needs_restart=["frontend"]) + except Exception as err: + return ActionResult(status="error", message=repr(err)) + + @staticmethod + def get_semver_version(version: str) -> str: + """Convert a Python version to Semver version. + + It: + + - drops ``.devN`` and ``.postN`` + - converts ``aN``, ``bN`` and ``rcN`` to ``-alpha.N``, ``-beta.N``, ``-rc.N`` respectively + + Args: + version: Version to convert + Returns + Semver compatible version + """ + return re.sub( + r"(a|b|rc)(\d+)$", + lambda m: f"{PYTHON_TO_SEMVER[m.group(1)]}{m.group(2)}", + re.subn(r"\.(dev|post)\d+", "", version)[0], + ) + + def get_normalized_name(self, extension: ExtensionPackage) -> str: + """Normalize extension name. + + Extension have multiple parts, npm package, Python package,... + Sub-classes may override this method to ensure the name of + an extension from the service provider and the local installed + listing is matching. + + Args: + extension: The extension metadata + Returns: + The normalized name + """ + return extension.name + + async def list_extensions( + self, query: Optional[str] = None, page: int = 1, per_page: int = 30 + ) -> Tuple[List[ExtensionPackage], Optional[int]]: + """List extensions for a given ``query`` search term. + + This will return the extensions installed (if ``query`` is None) or + available if allowed by the listing settings. + + Args: + query: [optional] Query search term. + + Returns: + The extensions + Last page of results + """ + if query not in self._extensions_cache or page not in self._extensions_cache[query].cache: + await self.refresh(query, page, per_page) + + # filter using listings settings + if self._listings_cache is None and self._listing_fetch is not None: + await self._listing_fetch.callback() + + cache = self._extensions_cache[query].cache[page] + if cache is None: + cache = {} + extensions = list(cache.values()) + if query is not None and self._listings_cache is not None: + listing = list(self._listings_cache) + extensions = [] + if self._listings_block_mode: + for name, ext in cache.items(): + if name not in listing: + extensions.append(replace(ext, allowed=True)) + elif ext.installed_version: + self.log.warning(f"Blocked extension '{name}' is installed.") + extensions.append(replace(ext, allowed=False)) + else: + for name, ext in cache.items(): + if name in listing: + extensions.append(replace(ext, allowed=True)) + elif ext.installed_version: + self.log.warning(f"Not allowed extension '{name}' is installed.") + extensions.append(replace(ext, allowed=False)) + + return extensions, self._extensions_cache[query].last_page + + async def refresh(self, query: Optional[str], page: int, per_page: int) -> None: + """Refresh the list of extensions.""" + if query in self._extensions_cache: + self._extensions_cache[query].cache[page] = None + await self._update_extensions_list(query, page, per_page) + + async def _fetch_listings(self) -> None: + """Fetch the listings for the extension manager.""" + rules = [] + client = tornado.httpclient.AsyncHTTPClient() + if self._listings_block_mode: + if len(self.options.blocked_extensions_uris): + self.log.info( + f"Fetching blocked extensions from {self.options.blocked_extensions_uris}" + ) + for blocked_extensions_uri in self.options.blocked_extensions_uris: + r = await client.fetch( + blocked_extensions_uri, + **self.options.listings_tornado_options, + ) + j = json.loads(r.body) + rules.extend(j.get("blocked_extensions", [])) + elif len(self.options.allowed_extensions_uris): + self.log.info( + f"Fetching allowed extensions from { self.options.allowed_extensions_uris}" + ) + for allowed_extensions_uri in self.options.allowed_extensions_uris: + r = await client.fetch( + allowed_extensions_uri, + **self.options.listings_tornado_options, + ) + j = json.loads(r.body) + rules.extend(j.get("allowed_extensions", [])) + + self._listings_cache = {r["name"]: r for r in rules} + + async def _get_installed_extensions( + self, get_latest_version=True + ) -> Dict[str, ExtensionPackage]: + """Get the installed extensions. + + Args: + get_latest_version: Whether to fetch the latest extension version or not. + Returns: + The installed extensions as a mapping {name: metadata} + """ + app_options = self.app_options + info = get_app_info(app_options=app_options) + build_check_info = _build_check_info(app_options) + _ensure_compat_errors(info, app_options) + extensions = {} + + # TODO: the three for-loops below can be run concurrently + for name, data in info["federated_extensions"].items(): + status = "ok" + pkg_info = data + if info["compat_errors"].get(name, None): + status = "error" + + normalized_name = self._normalize_name(name) + pkg = ExtensionPackage( + name=normalized_name, + description=pkg_info.get("description", ""), + homepage_url=data.get("url", ""), + enabled=(name not in info["disabled"]), + core=False, + latest_version=ExtensionManager.get_semver_version(data["version"]), + installed=True, + installed_version=ExtensionManager.get_semver_version(data["version"]), + status=status, + install=data.get("install", {}), + pkg_type="prebuilt", + companion=self._get_companion(data), + author=data.get("author", {}).get("name", data.get("author")), + license=data.get("license"), + bug_tracker_url=data.get("bugs", {}).get("url"), + repository_url=data.get("repository", {}).get("url", data.get("repository")), + ) + + if get_latest_version: + pkg = replace(pkg, latest_version=await self.get_latest_version(pkg.name)) + + extensions[normalized_name] = pkg + + for name, data in info["extensions"].items(): + if name in info["shadowed_exts"]: + continue + status = "ok" + + if info["compat_errors"].get(name, None): + status = "error" + else: + for packages in build_check_info.values(): + if name in packages: + status = "warning" + + normalized_name = self._normalize_name(name) + pkg = ExtensionPackage( + name=normalized_name, + description=data.get("description", ""), + homepage_url=data["url"], + enabled=(name not in info["disabled"]), + core=False, + latest_version=ExtensionManager.get_semver_version(data["version"]), + installed=True, + installed_version=ExtensionManager.get_semver_version(data["version"]), + status=status, + pkg_type="source", + companion=self._get_companion(data), + author=data.get("author", {}).get("name", data.get("author")), + license=data.get("license"), + bug_tracker_url=data.get("bugs", {}).get("url"), + repository_url=data.get("repository", {}).get("url", data.get("repository")), + ) + if get_latest_version: + pkg = replace(pkg, latest_version=await self.get_latest_version(pkg.name)) + extensions[normalized_name] = pkg + + for name in build_check_info["uninstall"]: + data = self._get_scheduled_uninstall_info(name) + if data is not None: + normalized_name = self._normalize_name(name) + pkg = ExtensionPackage( + name=normalized_name, + description=data.get("description", ""), + homepage_url=data.get("homepage", ""), + installed=False, + enabled=False, + core=False, + latest_version=ExtensionManager.get_semver_version(data["version"]), + installed_version=ExtensionManager.get_semver_version(data["version"]), + status="warning", + pkg_type="prebuilt", + author=data.get("author", {}).get("name", data.get("author")), + license=data.get("license"), + bug_tracker_url=data.get("bugs", {}).get("url"), + repository_url=data.get("repository", {}).get("url", data.get("repository")), + ) + extensions[normalized_name] = pkg + + return extensions + + def _get_companion(self, data: dict) -> Optional[str]: + companion = None + if "discovery" in data["jupyterlab"]: + if "server" in data["jupyterlab"]["discovery"]: + companion = "server" + elif "kernel" in data["jupyterlab"]["discovery"]: + companion = "kernel" + return companion + + def _get_scheduled_uninstall_info(self, name) -> Optional[dict]: + """Get information about a package that is scheduled for uninstallation""" + target = self.app_dir / "staging" / "node_modules" / name / "package.json" + if target.exists(): + with target.open() as fid: + return json.load(fid) + else: + return None + + def _normalize_name(self, name: str) -> str: + """Normalize extension name; by default does nothing. + + Args: + name: Extension name + Returns: + Normalized name + """ + return name + + async def _update_extensions_list( + self, query: Optional[str] = None, page: int = 1, per_page: int = 30 + ) -> None: + """Update the list of extensions""" + last_page = None + if query is not None: + # Get the available extensions + extensions, last_page = await self.list_packages(query, page, per_page) + else: + # Get the installed extensions + extensions = await self._get_installed_extensions() + + if query in self._extensions_cache: + self._extensions_cache[query].cache[page] = extensions + self._extensions_cache[query].last_page = last_page or 1 + else: + self._extensions_cache[query] = ExtensionsCache({page: extensions}, last_page or 1) diff --git a/jupyterlab/extensions/pypi.py b/jupyterlab/extensions/pypi.py new file mode 100644 index 000000000000..ef477440c56b --- /dev/null +++ b/jupyterlab/extensions/pypi.py @@ -0,0 +1,459 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +"""Extension manager using pip as package manager and PyPi.org as packages source.""" + +import asyncio +import io +import json +import math +import re +import sys +import xmlrpc.client +from datetime import datetime, timedelta, timezone +from functools import partial +from itertools import groupby +from pathlib import Path +from subprocess import CalledProcessError, run +from tarfile import TarFile +from typing import Any, Callable, Dict, List, Optional, Tuple +from zipfile import ZipFile + +import tornado +from async_lru import alru_cache +from traitlets import CFloat, CInt, Unicode, config, observe + +from jupyterlab.extensions.manager import ( + ActionResult, + ExtensionManager, + ExtensionManagerMetadata, + ExtensionPackage, +) + + +async def _fetch_package_metadata(name: str, latest_version: str, base_url: str) -> dict: + http_client = tornado.httpclient.AsyncHTTPClient() + response = await http_client.fetch( + base_url + f"/{name}/{latest_version}/json", + headers={"Content-Type": "application/json"}, + ) + data = json.loads(response.body).get("info") + + # Keep minimal information to limit cache size + return { + k: data.get(k) + for k in [ + "author", + "bugtrack_url", + "docs_url", + "home_page", + "license", + "package_url", + "project_url", + "project_urls", + "summary", + ] + } + + +class PyPIExtensionManager(ExtensionManager): + """Extension manager using pip as package manager and PyPi.org as packages source.""" + + base_url = Unicode("https://pypi.org/pypi", config=True, help="The base URL of PyPI index.") + + cache_timeout = CFloat( + 5 * 60.0, config=True, help="PyPI extensions list cache timeout in seconds." + ) + + package_metadata_cache_size = CInt( + 1500, config=True, help="The cache size for package metadata." + ) + + rpc_request_throttling = CFloat( + 1.0, + config=True, + help="Throttling time in seconds between PyPI requests using the XML-RPC API.", + ) + + def __init__( + self, + app_options: Optional[dict] = None, + ext_options: Optional[dict] = None, + parent: Optional[config.Configurable] = None, + ) -> None: + super().__init__(app_options, ext_options, parent) + # Set configurable cache size to fetch function + self._fetch_package_metadata = _fetch_package_metadata + self._observe_package_metadata_cache_size({"new": self.package_metadata_cache_size}) + # Combine XML RPC API and JSON API to reduce throttling by PyPI.org + self._http_client = tornado.httpclient.AsyncHTTPClient() + self._rpc_client = xmlrpc.client.ServerProxy(self.base_url) + self.__last_all_packages_request_time = datetime.now(tz=timezone.utc) - timedelta( + seconds=self.cache_timeout * 1.01 + ) + self.__all_packages_cache = None + + self.log.debug(f"Extensions list will be fetched from {self.base_url}.") + + @property + def metadata(self) -> ExtensionManagerMetadata: + """Extension manager metadata.""" + return ExtensionManagerMetadata("PyPI", True, sys.prefix) + + async def get_latest_version(self, pkg: str) -> Optional[str]: + """Return the latest available version for a given extension. + + Args: + pkg: The extension to search for + Returns: + The latest available version + """ + try: + http_client = tornado.httpclient.AsyncHTTPClient() + response = await http_client.fetch( + self.base_url + f"/{pkg}/json", + headers={"Content-Type": "application/json"}, + ) + data = json.loads(response.body).get("info") + except Exception: + return None + else: + return ExtensionManager.get_semver_version(data.get("version")) + + def get_normalized_name(self, extension: ExtensionPackage) -> str: + """Normalize extension name. + + Extension have multiple parts, npm package, Python package,... + Sub-classes may override this method to ensure the name of + an extension from the service provider and the local installed + listing is matching. + + Args: + extension: The extension metadata + Returns: + The normalized name + """ + if extension.install is not None: + install_metadata = extension.install + if install_metadata["packageManager"] == "python": + return self._normalize_name(install_metadata["packageName"]) + return self._normalize_name(extension.name) + + async def __throttleRequest(self, recursive: bool, fn: Callable, *args) -> Any: # noqa + """Throttle XMLRPC API request + + Args: + recursive: Whether to call the throttling recursively once or not. + fn: API method to call + *args: API method arguments + Returns: + Result of the method + Raises: + xmlrpc.client.Fault + """ + current_loop = tornado.ioloop.IOLoop.current() + try: + data = await current_loop.run_in_executor(None, fn, *args) + except xmlrpc.client.Fault as err: + if err.faultCode == -32500 and err.faultString.startswith( # noqa PLR2004 + "HTTPTooManyRequests:" + ): + delay = 1.01 + match = re.search(r"Limit may reset in (\d+) seconds.", err.faultString) + if match is not None: + delay = int(match.group(1) or "1") + self.log.info( + f"HTTPTooManyRequests - Perform next call to PyPI XMLRPC API in {delay}s." + ) + await asyncio.sleep(delay * self.rpc_request_throttling + 0.01) + if recursive: + data = await self.__throttleRequest(False, fn, *args) + else: + data = await current_loop.run_in_executor(None, fn, *args) + + return data + + @observe("package_metadata_cache_size") + def _observe_package_metadata_cache_size(self, change): + self._fetch_package_metadata = alru_cache(maxsize=change["new"])(_fetch_package_metadata) + + async def list_packages( + self, query: str, page: int, per_page: int + ) -> Tuple[Dict[str, ExtensionPackage], Optional[int]]: + """List the available extensions. + + Note: + This will list the packages based on the classifier + Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt + + Then it filters it with the query + + We do not try to check if they are compatible (version wise) + + Args: + query: The search extension query + page: The result page + per_page: The number of results per page + Returns: + The available extensions in a mapping {name: metadata} + The results last page; None if the manager does not support pagination + """ + matches = await self.__get_all_extensions() + + extensions = {} + + counter = -1 + min_index = (page - 1) * per_page + max_index = page * per_page + for name, group in groupby(filter(lambda m: query in m[0], matches), lambda e: e[0]): + counter += 1 + if counter < min_index or counter >= max_index: + continue + + _, latest_version = list(group)[-1] + data = await self._fetch_package_metadata(name, latest_version, self.base_url) + + normalized_name = self._normalize_name(name) + + package_urls = data.get("project_urls") or {} + + source_url = package_urls.get("Source Code") + homepage_url = data.get("home_page") or package_urls.get("Homepage") + documentation_url = data.get("docs_url") or package_urls.get("Documentation") + bug_tracker_url = data.get("bugtrack_url") or package_urls.get("Bug Tracker") + + best_guess_home_url = ( + homepage_url + or data.get("project_url") + or data.get("package_url") + or documentation_url + or source_url + or bug_tracker_url + ) + + extensions[normalized_name] = ExtensionPackage( + name=normalized_name, + description=data.get("summary"), + homepage_url=best_guess_home_url, + author=data.get("author"), + license=data.get("license"), + latest_version=ExtensionManager.get_semver_version(latest_version), + pkg_type="prebuilt", + bug_tracker_url=bug_tracker_url, + documentation_url=documentation_url, + package_manager_url=data.get("package_url"), + repository_url=source_url, + ) + + return extensions, math.ceil((counter + 1) / per_page) + + async def __get_all_extensions(self) -> List[Tuple[str, str]]: + if self.__all_packages_cache is None or datetime.now( + tz=timezone.utc + ) > self.__last_all_packages_request_time + timedelta(seconds=self.cache_timeout): + self.log.debug("Requesting PyPI.org RPC API for prebuilt JupyterLab extensions.") + self.__all_packages_cache = await self.__throttleRequest( + True, + self._rpc_client.browse, + ["Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt"], + ) + self.__last_all_packages_request_time = datetime.now(tz=timezone.utc) + + return self.__all_packages_cache + + async def install(self, name: str, version: Optional[str] = None) -> ActionResult: # noqa + """Install the required extension. + + Note: + If the user must be notified with a message (like asking to restart the + server), the result should be + {"status": "warning", "message": ""} + + Args: + name: The extension name + version: The version to install; default None (i.e. the latest possible) + Returns: + The action result + """ + current_loop = tornado.ioloop.IOLoop.current() + + cmdline = [ + sys.executable, + "-m", + "pip", + "install", + "--no-input", + "--quiet", + "--progress-bar", + "off", + ] + if version is not None: + cmdline.append(f"{name}=={version}") + else: + cmdline.append(name) + + pkg_action = {} + try: + tmp_cmd = cmdline.copy() + tmp_cmd.insert(-1, "--dry-run") + tmp_cmd.insert(-1, "--report") + tmp_cmd.insert(-1, "-") + result = await current_loop.run_in_executor( + None, partial(run, tmp_cmd, capture_output=True, check=True) + ) + + action_info = json.loads(result.stdout.decode("utf-8")) + pkg_action = next( + iter( + filter( + lambda p: p.get("metadata", {}).get("name") == name.replace("_", "-"), + action_info.get("install", []), + ) + ) + ) + except CalledProcessError as e: + self.log.debug(f"Fail to get installation report: {e.stderr}", exc_info=e) + except Exception as err: + self.log.debug("Fail to get installation report.", exc_info=err) + else: + self.log.debug(f"Actions to be executed by pip {json.dumps(action_info)}.") + + self.log.debug(f"Executing '{' '.join(cmdline)}'") + + result = await current_loop.run_in_executor( + None, partial(run, cmdline, capture_output=True) + ) + + self.log.debug(f"return code: {result.returncode}") + self.log.debug(f"stdout: {result.stdout.decode('utf-8')}") + error = result.stderr.decode("utf-8") + if result.returncode == 0: + self.log.debug(f"stderr: {error}") + # Figure out if the package has server or kernel parts + jlab_metadata = None + try: + download_url: str = pkg_action.get("download_info", {}).get("url") + if download_url is not None: + response = await self._http_client.fetch(download_url) + if download_url.endswith(".whl"): + with ZipFile(io.BytesIO(response.body)) as wheel: + for name in filter( + lambda f: Path(f).name == "package.json", + wheel.namelist(), + ): + data = json.loads(wheel.read(name)) + jlab_metadata = data.get("jupyterlab") + if jlab_metadata is not None: + break + elif download_url.endswith("tar.gz"): + with TarFile(io.BytesIO(response.body)) as sdist: + for name in filter( + lambda f: Path(f).name == "package.json", + sdist.getnames(), + ): + data = json.load(sdist.extractfile(sdist.getmember(name))) + jlab_metadata = data.get("jupyterlab") + if jlab_metadata is not None: + break + except Exception as e: + self.log.debug("Fail to get package.json.", exc_info=e) + + follow_ups = [ + "frontend", + ] + if jlab_metadata is not None: + discovery = jlab_metadata.get("discovery", {}) + if "kernel" in discovery: + follow_ups.append("kernel") + if "server" in discovery: + follow_ups.append("server") + + return ActionResult(status="ok", needs_restart=follow_ups) + else: + self.log.error(f"Failed to installed {name}: code {result.returncode}\n{error}") + return ActionResult(status="error", message=error) + + async def uninstall(self, extension: str) -> ActionResult: + """Uninstall the required extension. + + Note: + If the user must be notified with a message (like asking to restart the + server), the result should be + {"status": "warning", "message": ""} + + Args: + extension: The extension name + Returns: + The action result + """ + current_loop = tornado.ioloop.IOLoop.current() + cmdline = [ + sys.executable, + "-m", + "pip", + "uninstall", + "--yes", + "--no-input", + extension, + ] + + # Figure out if the package has server or kernel parts + jlab_metadata = None + try: + tmp_cmd = cmdline.copy() + tmp_cmd.remove("--yes") + result = await current_loop.run_in_executor( + None, partial(run, tmp_cmd, capture_output=True) + ) + lines = filter( + lambda line: line.endswith("package.json"), + map(lambda line: line.strip(), result.stdout.decode("utf-8").splitlines()), # noqa + ) + for filepath in filter( + lambda f: f.name == "package.json", + map(Path, lines), + ): + data = json.loads(filepath.read_bytes()) + jlab_metadata = data.get("jupyterlab") + if jlab_metadata is not None: + break + except Exception as e: + self.log.debug("Fail to list files to be uninstalled.", exc_info=e) + + self.log.debug(f"Executing '{' '.join(cmdline)}'") + + result = await current_loop.run_in_executor( + None, partial(run, cmdline, capture_output=True) + ) + + self.log.debug(f"return code: {result.returncode}") + self.log.debug(f"stdout: {result.stdout.decode('utf-8')}") + error = result.stderr.decode("utf-8") + if result.returncode == 0: + self.log.debug(f"stderr: {error}") + follow_ups = [ + "frontend", + ] + if jlab_metadata is not None: + discovery = jlab_metadata.get("discovery", {}) + if "kernel" in discovery: + follow_ups.append("kernel") + if "server" in discovery: + follow_ups.append("server") + + return ActionResult(status="ok", needs_restart=follow_ups) + else: + self.log.error(f"Failed to installed {extension}: code {result.returncode}\n{error}") + return ActionResult(status="error", message=error) + + def _normalize_name(self, name: str) -> str: + """Normalize extension name. + + Remove `@` from npm scope and replace `/` and `_` by `-`. + + Args: + name: Extension name + Returns: + Normalized name + """ + return name.replace("@", "").replace("/", "-").replace("_", "-") diff --git a/jupyterlab/extensions/readonly.py b/jupyterlab/extensions/readonly.py new file mode 100644 index 000000000000..1dbdef1db503 --- /dev/null +++ b/jupyterlab/extensions/readonly.py @@ -0,0 +1,82 @@ +"""Extension manager without installation capabilities.""" + +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +import sys +from typing import Dict, Optional, Tuple + +from jupyterlab_server.translation_utils import translator + +from .manager import ActionResult, ExtensionManager, ExtensionManagerMetadata, ExtensionPackage + + +class ReadOnlyExtensionManager(ExtensionManager): + """Extension manager without installation capabilities.""" + + @property + def metadata(self) -> ExtensionManagerMetadata: + """Extension manager metadata.""" + return ExtensionManagerMetadata("read-only", install_path=sys.prefix) + + async def get_latest_version(self, pkg: str) -> Optional[str]: + """Return the latest available version for a given extension. + + Args: + pkg: The extension to search for + Returns: + The latest available version + """ + return None + + async def list_packages( + self, query: str, page: int, per_page: int + ) -> Tuple[Dict[str, ExtensionPackage], Optional[int]]: + """List the available extensions. + + Args: + query: The search extension query + page: The result page + per_page: The number of results per page + Returns: + The available extensions in a mapping {name: metadata} + The results last page; None if the manager does not support pagination + """ + return {}, None + + async def install(self, extension: str, version: Optional[str] = None) -> ActionResult: + """Install the required extension. + + Note: + If the user must be notified with a message (like asking to restart the + server), the result should be + {"status": "warning", "message": ""} + + Args: + extension: The extension name + version: The version to install; default None (i.e. the latest possible) + Returns: + The action result + """ + trans = translator.load("jupyterlab") + return ActionResult( + status="error", message=trans.gettext("Extension installation not supported.") + ) + + async def uninstall(self, extension: str) -> ActionResult: + """Uninstall the required extension. + + Note: + If the user must be notified with a message (like asking to restart the + server), the result should be + {"status": "warning", "message": ""} + + Args: + extension: The extension name + Returns: + The action result + """ + trans = translator.load("jupyterlab") + return ActionResult( + status="error", message=trans.gettext("Extension removal not supported.") + ) diff --git a/jupyterlab/federated_labextensions.py b/jupyterlab/federated_labextensions.py index a6935268bd9e..f5caac220e7b 100644 --- a/jupyterlab/federated_labextensions.py +++ b/jupyterlab/federated_labextensions.py @@ -1,10 +1,8 @@ -# coding: utf-8 """Utilities for installing Javascript extensions for the notebook""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from __future__ import print_function import importlib import json @@ -16,9 +14,13 @@ import sys from pathlib import Path -from os.path import basename +try: + from importlib.metadata import PackageNotFoundError, version +except ImportError: + from importlib_metadata import PackageNotFoundError, version + +from os.path import basename, normpath from os.path import join as pjoin -from os.path import normpath from jupyter_core.paths import ENV_JUPYTER_PATH, SYSTEM_JUPYTER_PATH, jupyter_data_dir from jupyter_core.utils import ensure_dir_exists @@ -42,7 +44,7 @@ # ------------------------------------------------------------------------------ -def develop_labextension( +def develop_labextension( # noqa path, symlink=True, overwrite=False, @@ -92,9 +94,8 @@ def develop_labextension( ensure_dir_exists(labext) if isinstance(path, (list, tuple)): - raise TypeError( - "path must be a string pointing to a single extension to install; call this function multiple times to install multiple extensions" - ) + msg = "path must be a string pointing to a single extension to install; call this function multiple times to install multiple extensions" + raise TypeError(msg) if not destination: destination = basename(normpath(path)) @@ -115,16 +116,17 @@ def develop_labextension( path = os.path.abspath(path) if not os.path.exists(full_dest): if logger: - logger.info("Symlinking: %s -> %s" % (full_dest, path)) + logger.info(f"Symlinking: {full_dest} -> {path}") try: os.symlink(path, full_dest) except OSError as e: if platform.platform().startswith("Windows"): - raise OSError( + msg = ( "Symlinks can be activated on Windows 10 for Python version 3.8 or higher" " by activating the 'Developer Mode'. That may not be allowed by your administrators.\n" "See https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development" - ) from e + ) + raise OSError(msg) from e raise elif not os.path.islink(full_dest): @@ -132,7 +134,7 @@ def develop_labextension( elif os.path.isdir(path): path = pjoin(os.path.abspath(path), "") # end in path separator - for parent, dirs, files in os.walk(path): + for parent, _, files in os.walk(path): dest_dir = pjoin(full_dest, parent[len(path) :]) if not os.path.exists(dest_dir): if logger: @@ -172,7 +174,7 @@ def develop_labextension_py( src = os.path.join(base_path, labext["src"]) dest = labext["dest"] if logger: - logger.info("Installing %s -> %s" % (src, dest)) + logger.info(f"Installing {src} -> {dest}") if not os.path.exists(src): build_labextension(base_path, logger=logger) @@ -196,12 +198,9 @@ def build_labextension( path, logger=None, development=False, static_url=None, source_map=False, core_path=None ): """Build a labextension in the given path""" - if core_path is None: - core_path = osp.join(HERE, "staging") - else: - core_path = str(Path(core_path).resolve()) + core_path = osp.join(HERE, "staging") if core_path is None else str(Path(core_path).resolve()) - ext_path = osp.abspath(path) + ext_path = str(Path(path).resolve()) if logger: logger.info("Building extension in %s" % path) @@ -216,18 +215,15 @@ def build_labextension( if source_map: arguments.append("--source-map") - subprocess.check_call(arguments, cwd=ext_path) + subprocess.check_call(arguments, cwd=ext_path) # noqa S603 def watch_labextension( path, labextensions_path, logger=None, development=False, source_map=False, core_path=None ): """Watch a labextension in a given path""" - if core_path is None: - core_path = osp.join(HERE, "staging") - else: - core_path = str(Path(core_path).resolve()) - ext_path = osp.abspath(path) + core_path = osp.join(HERE, "staging") if core_path is None else str(Path(core_path).resolve()) + ext_path = str(Path(path).resolve()) if logger: logger.info("Building extension in %s" % path) @@ -254,7 +250,7 @@ def watch_labextension( if source_map: arguments.append("--source-map") - subprocess.check_call(arguments, cwd=ext_path) + subprocess.check_call(arguments, cwd=ext_path) # noqa S603 # ------------------------------------------------------------------------------ @@ -269,45 +265,46 @@ def _ensure_builder(ext_path, core_path): core_data = json.load(fid) with open(osp.join(ext_path, "package.json")) as fid: ext_data = json.load(fid) - depVersion1 = core_data["devDependencies"]["@jupyterlab/builder"] - depVersion2 = ext_data.get("devDependencies", dict()).get("@jupyterlab/builder") - depVersion2 = depVersion2 or ext_data.get("dependencies", dict()).get("@jupyterlab/builder") - if depVersion2 is None: + dep_version1 = core_data["devDependencies"]["@jupyterlab/builder"] + dep_version2 = ext_data.get("devDependencies", {}).get("@jupyterlab/builder") + dep_version2 = dep_version2 or ext_data.get("dependencies", {}).get("@jupyterlab/builder") + if dep_version2 is None: raise ValueError( - "Extensions require a devDependency on @jupyterlab/builder@%s" % depVersion1 + "Extensions require a devDependency on @jupyterlab/builder@%s" % dep_version1 ) # if we have installed from disk (version is a path), assume we know what # we are doing and do not check versions. - if "/" in depVersion2: - with open(osp.join(ext_path, depVersion2, "package.json")) as fid: - depVersion2 = json.load(fid).get("version") + if "/" in dep_version2: + with open(osp.join(ext_path, dep_version2, "package.json")) as fid: + dep_version2 = json.load(fid).get("version") if not osp.exists(osp.join(ext_path, "node_modules")): - subprocess.check_call(["jlpm"], cwd=ext_path) + subprocess.check_call(["jlpm"], cwd=ext_path) # noqa S603 S607 # Find @jupyterlab/builder using node module resolution # We cannot use a script because the script path is a shell script on Windows target = ext_path while not osp.exists(osp.join(target, "node_modules", "@jupyterlab", "builder")): if osp.dirname(target) == target: - raise ValueError("Could not find @jupyterlab/builder") + msg = "Could not find @jupyterlab/builder" + raise ValueError(msg) target = osp.dirname(target) - overlap = _test_overlap(depVersion1, depVersion2, drop_prerelease1=True, drop_prerelease2=True) + overlap = _test_overlap( + dep_version1, dep_version2, drop_prerelease1=True, drop_prerelease2=True + ) if not overlap: with open( osp.join(target, "node_modules", "@jupyterlab", "builder", "package.json") ) as fid: - depVersion2 = json.load(fid).get("version") + dep_version2 = json.load(fid).get("version") overlap = _test_overlap( - depVersion1, depVersion2, drop_prerelease1=True, drop_prerelease2=True + dep_version1, dep_version2, drop_prerelease1=True, drop_prerelease2=True ) if not overlap: - raise ValueError( - "Extensions require a devDependency on @jupyterlab/builder@%s, you have a dependency on %s" - % (depVersion1, depVersion2) - ) + msg = f"Extensions require a devDependency on @jupyterlab/builder@{dep_version1}, you have a dependency on {dep_version2}" + raise ValueError(msg) return osp.join( target, "node_modules", "@jupyterlab", "builder", "lib", "build-labextension.js" @@ -331,11 +328,11 @@ def _should_copy(src, dest, logger=None): """ if not os.path.exists(dest): return True - if os.stat(src).st_mtime - os.stat(dest).st_mtime > 1e-6: + if os.stat(src).st_mtime - os.stat(dest).st_mtime > 1e-6: # noqa # we add a fudge factor to work around a bug in python 2.x # that was fixed in python 3.x: https://bugs.python.org/issue12904 if logger: - logger.warn("Out of date: %s" % dest) + logger.warning("Out of date: %s" % dest) return True if logger: logger.info("Up to date: %s" % dest) @@ -357,7 +354,7 @@ def _maybe_copy(src, dest, logger=None): """ if _should_copy(src, dest, logger=logger): if logger: - logger.info("Copying: %s -> %s" % (src, dest)) + logger.info(f"Copying: {src} -> {dest}") shutil.copy2(src, dest) @@ -382,13 +379,12 @@ def _get_labextension_dir(user=False, sys_prefix=False, prefix=None, labextensio ("labextensions_dir", labextensions_dir), ("sys_prefix", sys_prefix), ] - conflicting_set = ["{}={!r}".format(n, v) for n, v in conflicting if v] + conflicting_set = [f"{n}={v!r}" for n, v in conflicting if v] if len(conflicting_set) > 1: - raise ArgumentConflict( - "cannot specify more than one of user, sys_prefix, prefix, or labextensions_dir, but got: {}".format( - ", ".join(conflicting_set) - ) + msg = "cannot specify more than one of user, sys_prefix, prefix, or labextensions_dir, but got: {}".format( + ", ".join(conflicting_set) ) + raise ArgumentConflict(msg) if user: labext = pjoin(jupyter_data_dir(), "labextensions") elif sys_prefix: @@ -402,7 +398,7 @@ def _get_labextension_dir(user=False, sys_prefix=False, prefix=None, labextensio return labext -def _get_labextension_metadata(module): +def _get_labextension_metadata(module): # noqa """Get the list of labextension paths associated with a Python module. Returns a tuple of (the module path, [{ @@ -419,7 +415,8 @@ def _get_labextension_metadata(module): """ mod_path = osp.abspath(module) if not osp.exists(mod_path): - raise FileNotFoundError("The path `{}` does not exist.".format(mod_path)) + msg = f"The path `{mod_path}` does not exist." + raise FileNotFoundError(msg) errors = [] @@ -431,7 +428,7 @@ def _get_labextension_metadata(module): except Exception as exc: errors.append(exc) - # Try to get the package name + # Try to get the package name package = None # Try getting the package name from pyproject.toml @@ -440,27 +437,28 @@ def _get_labextension_metadata(module): data = load(fid) package = data.get("project", {}).get("name") - # Try getting the package name from setup.py invocation. + # Try getting the package name from setup.py if not package: try: package = ( - subprocess.check_output([sys.executable, "setup.py", "--name"], cwd=mod_path) + subprocess.check_output( + [sys.executable, "setup.py", "--name"], cwd=mod_path # noqa S603 + ) .decode("utf8") .strip() ) except subprocess.CalledProcessError: - raise FileNotFoundError( - "The Python package `{}` is not a valid package, " - "it is missing the `setup.py` file.".format(module) + msg = ( + f"The Python package `{module}` is not a valid package, " + "it is missing the `setup.py` file." ) + raise FileNotFoundError(msg) from None # Make sure the package is installed - import pkg_resources - try: - pkg_resources.get_distribution(package) - except pkg_resources.DistributionNotFound: - subprocess.check_call([sys.executable, "-m", "pip", "install", "-e", mod_path]) + version(package) + except PackageNotFoundError: + subprocess.check_call([sys.executable, "-m", "pip", "install", "-e", mod_path]) # noqa S603 sys.path.insert(0, mod_path) from setuptools import find_namespace_packages, find_packages @@ -481,6 +479,5 @@ def _get_labextension_metadata(module): except Exception as exc: errors.append(exc) - raise ModuleNotFoundError( - "There is no labextension at {}. Errors encountered: {}".format(module, errors) - ) + msg = f"There is no labextension at {module}. Errors encountered: {errors}" + raise ModuleNotFoundError(msg) diff --git a/jupyterlab/galata/__init__.py b/jupyterlab/galata/__init__.py new file mode 100644 index 000000000000..480bfaf9d030 --- /dev/null +++ b/jupyterlab/galata/__init__.py @@ -0,0 +1,40 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +import getpass +import os +from pathlib import Path +from tempfile import mkdtemp + + +def configure_jupyter_server(c): + """Helper to configure the Jupyter Server for integration testing + with Galata. + + By default the tests will be executed in the OS temporary folder. You + can override that folder by setting the environment variable ``JUPYTERLAB_GALATA_ROOT_DIR``. + + .. warning:: + + Never use this configuration in production as it will remove all security protections. + """ + # Test if we are running in a docker + if getpass.getuser() == "jovyan": + c.ServerApp.ip = "0.0.0.0" # noqa S104 + + c.ServerApp.port = 8888 + c.ServerApp.port_retries = 0 + c.ServerApp.open_browser = False + # Add test helpers extension shipped with JupyterLab. + # You can replace the following line by the two following one + # import jupyterlab + # c.LabServerApp.extra_labextensions_path = str(Path(jupyterlab.__file__).parent / "galata") + c.LabServerApp.extra_labextensions_path = str(Path(__file__).parent) + + c.ServerApp.root_dir = os.environ.get( + "JUPYTERLAB_GALATA_ROOT_DIR", mkdtemp(prefix="galata-test-") + ) + c.ServerApp.token = "" + c.ServerApp.password = "" + c.ServerApp.disable_check_xsrf = True + c.LabApp.expose_app_in_browser = True diff --git a/jupyterlab/handlers/__init__.py b/jupyterlab/handlers/__init__.py index e69de29bb2d1..c1463008fe10 100644 --- a/jupyterlab/handlers/__init__.py +++ b/jupyterlab/handlers/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. diff --git a/jupyterlab/handlers/announcements.py b/jupyterlab/handlers/announcements.py index bd72e8af7588..e94d68cefc5e 100644 --- a/jupyterlab/handlers/announcements.py +++ b/jupyterlab/handlers/announcements.py @@ -6,9 +6,9 @@ import abc import hashlib import json -import xml.etree.ElementTree as ET +import xml.etree.ElementTree as ET # noqa from dataclasses import asdict, dataclass, field -from datetime import datetime +from datetime import datetime, timezone from typing import Awaitable, Optional, Tuple, Union from jupyter_server.base.handlers import APIHandler @@ -16,7 +16,7 @@ from packaging.version import parse from tornado import httpclient, web -from .._version import __version__ +from jupyterlab._version import __version__ ISO8601_FORMAT = "%Y-%m-%dT%H:%M:%S%z" JUPYTERLAB_LAST_RELEASE_URL = "https://pypi.org/pypi/jupyterlab/json" @@ -40,10 +40,10 @@ class Notification: options: Notification options """ - createdAt: float + createdAt: float # noqa message: str - modifiedAt: float - type: str = "default" + modifiedAt: float # noqa + type: str = "default" # noqa link: Tuple[str, str] = field(default_factory=tuple) options: dict = field(default_factory=dict) @@ -71,7 +71,8 @@ async def __call__(self) -> Awaitable[Union[None, str, Tuple[str, Tuple[str, str or the notification message or the notification message and a tuple(label, URL link) for the user to get more information """ - raise NotImplementedError("CheckForUpdateABC.__call__ is not implemented") + msg = "CheckForUpdateABC.__call__ is not implemented" + raise NotImplementedError(msg) class CheckForUpdate(CheckForUpdateABC): @@ -169,15 +170,15 @@ async def get(self): out = await self.update_checker() if out: message, link = (out, ()) if isinstance(out, str) else out - now = datetime.now().timestamp() * 1000.0 - hash = hashlib.sha1(message.encode()).hexdigest() + now = datetime.now(tz=timezone.utc).timestamp() * 1000.0 + hash_ = hashlib.sha1(message.encode()).hexdigest() # noqa: S324 notification = Notification( message=message, createdAt=now, modifiedAt=now, type="info", link=link, - options={"data": {"id": hash, "tags": ["update"]}}, + options={"data": {"id": hash_, "tags": ["update"]}}, ) self.set_status(200) @@ -226,7 +227,7 @@ async def get(self): self.news_url, headers={"Content-Type": "application/atom+xml"}, ) - tree = ET.fromstring(response.body) + tree = ET.fromstring(response.body) # noqa S314 def build_entry(node): def get_xml_text(attr: str, default: Optional[str] = None) -> str: diff --git a/jupyterlab/handlers/build_handler.py b/jupyterlab/handlers/build_handler.py index 2812da2eccec..52a2f8da7e5f 100644 --- a/jupyterlab/handlers/build_handler.py +++ b/jupyterlab/handlers/build_handler.py @@ -11,11 +11,10 @@ from tornado import gen, web from tornado.concurrent import run_on_executor -from ..commands import AppOptions, _ensure_options, build, build_check, clean -from ..coreconfig import CoreConfig +from jupyterlab.commands import AppOptions, _ensure_options, build, build_check, clean -class Builder(object): +class Builder: building = False executor = ThreadPoolExecutor(max_workers=5) canceled = False @@ -34,9 +33,9 @@ def __init__(self, core_mode, app_options=None): @gen.coroutine def get_status(self): if self.core_mode: - raise gen.Return(dict(status="stable", message="")) + raise gen.Return({"status": "stable", "message": ""}) if self.building: - raise gen.Return(dict(status="building", message="")) + raise gen.Return({"status": "building", "message": ""}) try: messages = yield self._run_build_check( @@ -44,21 +43,22 @@ def get_status(self): ) status = "needed" if messages else "stable" if messages: - self.log.warn("Build recommended") - [self.log.warn(m) for m in messages] + self.log.warning("Build recommended") + [self.log.warning(m) for m in messages] else: self.log.info("Build is up to date") - except ValueError as e: - self.log.warn("Could not determine jupyterlab build status without nodejs") + except ValueError: + self.log.warning("Could not determine jupyterlab build status without nodejs") status = "stable" messages = [] - raise gen.Return(dict(status=status, message="\n".join(messages))) + raise gen.Return({"status": status, "message": "\n".join(messages)}) @gen.coroutine def build(self): if self._canceling: - raise ValueError("Cancel in progress") + msg = "Cancel in progress" + raise ValueError(msg) if not self.building: self.canceled = False self._future = future = gen.Future() @@ -84,7 +84,8 @@ def build(self): @gen.coroutine def cancel(self): if not self.building: - raise ValueError("No current build") + msg = "No current build" + raise ValueError(msg) self._canceling = True yield self._future self._canceling = False @@ -112,17 +113,17 @@ def _run_build(self, app_dir, logger, kill_event, core_config, labextensions_pat ) try: return build(app_options=app_options) - except Exception as e: + except Exception: if self._kill_event.is_set(): return - self.log.warn("Build failed, running a clean and rebuild") + self.log.warning("Build failed, running a clean and rebuild") clean(app_options=app_options) return build(app_options=app_options) class BuildHandler(ExtensionHandlerMixin, APIHandler): def initialize(self, builder=None, name=None): - super(BuildHandler, self).initialize(name=name) + super().initialize(name=name) self.builder = builder @web.authenticated @@ -138,7 +139,7 @@ def delete(self): try: yield self.builder.cancel() except Exception as e: - raise web.HTTPError(500, str(e)) + raise web.HTTPError(500, str(e)) from None self.set_status(204) @web.authenticated @@ -148,7 +149,7 @@ def post(self): try: yield self.builder.build() except Exception as e: - raise web.HTTPError(500, str(e)) + raise web.HTTPError(500, str(e)) from None if self.builder.canceled: raise web.HTTPError(400, "Build canceled") diff --git a/jupyterlab/handlers/error_handler.py b/jupyterlab/handlers/error_handler.py index 43f1dc3e722b..f2d936ba2bc9 100644 --- a/jupyterlab/handlers/error_handler.py +++ b/jupyterlab/handlers/error_handler.py @@ -1,11 +1,10 @@ -# coding: utf-8 """An error handler for JupyterLab.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +from jupyter_server.base.handlers import JupyterHandler from jupyter_server.extension.handler import ExtensionHandlerMixin -from jupyterlab_server.server import JupyterHandler from tornado import web TEMPLATE = """ @@ -24,7 +23,7 @@ class ErrorHandler(ExtensionHandlerMixin, JupyterHandler): def initialize(self, messages=None, name=None): - super(ErrorHandler, self).initialize(name=name) + super().initialize(name=name) self.messages = messages @web.authenticated diff --git a/jupyterlab/handlers/extension_manager_handler.py b/jupyterlab/handlers/extension_manager_handler.py index 0ee37ddef494..b4e1977f1947 100644 --- a/jupyterlab/handlers/extension_manager_handler.py +++ b/jupyterlab/handlers/extension_manager_handler.py @@ -3,322 +3,137 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import dataclasses import json -import os -import re -from concurrent.futures import ThreadPoolExecutor +from urllib.parse import urlencode, urlunparse from jupyter_server.base.handlers import APIHandler -from jupyter_server.extension.handler import ExtensionHandlerMixin -from tornado import gen, web +from tornado import web -from ..commands import ( - AppOptions, - _AppHandler, - _ensure_options, - disable_extension, - enable_extension, - get_app_info, - get_latest_compatible_package_versions, - install_extension, - read_package, - uninstall_extension, -) +from jupyterlab.extensions.manager import ExtensionManager -def _make_extension_entry( - name, - description, - url, - enabled, - core, - latest_version, - installed_version, - status, - pkg_type, - installed=None, - install=None, -): - """Create an extension entry that can be sent to the client""" - ret = dict( - name=name, - description=description, - url=url, - enabled=enabled, - core=core, - latest_version=latest_version, - installed_version=installed_version, - status=status, - pkg_type=pkg_type, - ) - if installed is not None: - ret["installed"] = installed - if install is not None: - ret["install"] = install - return ret - - -def _ensure_compat_errors(info, app_options): - """Ensure that the app info has compat_errors field""" - handler = _AppHandler(app_options) - info["compat_errors"] = handler._get_extension_compat() - - -_message_map = { - "install": re.compile(r"(?P.*) needs to be included in build"), - "uninstall": re.compile(r"(?P.*) needs to be removed from build"), - "update": re.compile(r"(?P.*) changed from (?P.*) to (?P.*)"), -} - - -def _build_check_info(app_options): - """Get info about packages scheduled for (un)install/update""" - handler = _AppHandler(app_options) - messages = handler.build_check(fast=True) - # Decode the messages into a dict: - status = {"install": [], "uninstall": [], "update": []} - for msg in messages: - for key, pattern in _message_map.items(): - match = pattern.match(msg) - if match: - status[key].append(match.group("name")) - return status - - -class ExtensionManager(object): - executor = ThreadPoolExecutor(max_workers=1) - - def __init__(self, app_options=None): - app_options = _ensure_options(app_options) - self.log = app_options.logger - self.app_dir = app_options.app_dir - self.core_config = app_options.core_config - self.app_options = app_options - self._outdated = None - # To start fetching data on outdated extensions immediately, uncomment: - # IOLoop.current().spawn_callback(self._get_outdated) - - @gen.coroutine - def list_extensions(self): - """Handle a request for all installed extensions""" - app_options = self.app_options - info = get_app_info(app_options=app_options) - build_check_info = _build_check_info(app_options) - _ensure_compat_errors(info, app_options) - extensions = [] +class ExtensionHandler(APIHandler): + def initialize(self, manager: ExtensionManager): + super().initialize() + self.manager = manager - # TODO: the three for-loops below can be run concurrently - for name, data in info["federated_extensions"].items(): - status = "ok" - pkg_info = data # yield self._get_pkg_info(name, data) - if info["compat_errors"].get(name, None): - status = "error" - extensions.append( - _make_extension_entry( - name=name, - description=pkg_info.get("description", ""), - url=data.get("url", ""), - enabled=(name not in info["disabled"]), - core=False, - # Use wanted version to ensure we limit ourselves - # within semver restrictions - latest_version=data["version"], - installed_version=data["version"], - status=status, - install=data.get("install", {}), - pkg_type="prebuilt", + @web.authenticated + async def get(self): + """GET query returns info on extensions + + Query arguments: + refresh: [optional] Force refreshing the list of extensions - ["0", "1"]; default 0 + query: [optional] Query to search for extensions - default None (i.e. returns installed extensions) + page: [optional] Result page - default 1 (min. 1) + per_page: [optional] Number of results per page - default 30 (max. 100) + """ + query = self.get_argument("query", None) + page = max(1, int(self.get_argument("page", "1"))) + per_page = min(100, int(self.get_argument("per_page", "30"))) + if self.get_argument("refresh", "0") == "1": + await self.manager.refresh(query, page, per_page) + + extensions, last_page = await self.manager.list_extensions(query, page, per_page) + + self.set_status(200) + if last_page is not None: + links = [] + query_args = {"page": last_page, "per_page": per_page} + if query is not None: + query_args["query"] = query + last = urlunparse( + ( + self.request.protocol, + self.request.host, + self.request.path, + "", + urlencode(query_args, doseq=True), + "", ) ) - - for name, data in info["extensions"].items(): - if name in info["shadowed_exts"]: - continue - status = "ok" - pkg_info = yield self._get_pkg_info(name, data) - if info["compat_errors"].get(name, None): - status = "error" - else: - for packages in build_check_info.values(): - if name in packages: - status = "warning" - extensions.append( - _make_extension_entry( - name=name, - description=pkg_info.get("description", ""), - url=data["url"], - enabled=(name not in info["disabled"]), - core=False, - # Use wanted version to ensure we limit ourselves - # within semver restrictions - latest_version=pkg_info["latest_version"], - installed_version=data["version"], - status=status, - pkg_type="source", + links.append(f'<{last}>; rel="last"') + if page > 1: + query_args["page"] = max(1, page - 1) + prev = urlunparse( + ( + self.request.protocol, + self.request.host, + self.request.path, + "", + urlencode(query_args, doseq=True), + "", + ) ) - ) - for name in build_check_info["uninstall"]: - data = yield self._get_scheduled_uninstall_info(name) - if data is not None: - extensions.append( - _make_extension_entry( - name=name, - description=data.get("description", ""), - url=data.get("homepage", ""), - installed=False, - enabled=False, - core=False, - latest_version=data["version"], - installed_version=data["version"], - status="warning", - pkg_type="prebuilt", + links.append(f'<{prev}>; rel="prev"') + if page < last_page: + query_args["page"] = min(page + 1, last_page) + next_ = urlunparse( + ( + self.request.protocol, + self.request.host, + self.request.path, + "", + urlencode(query_args, doseq=True), + "", ) ) - raise gen.Return(extensions) - - @gen.coroutine - def install(self, extension): - """Handle an install/update request""" - try: - install_extension(extension, app_options=self.app_options) - except ValueError as e: - raise gen.Return(dict(status="error", message=str(e))) - raise gen.Return( - dict( - status="ok", - ) - ) - - @gen.coroutine - def uninstall(self, extension): - """Handle an uninstall request""" - did_uninstall = uninstall_extension(extension, app_options=self.app_options) - raise gen.Return( - dict( - status="ok" if did_uninstall else "error", - ) - ) - - @gen.coroutine - def enable(self, extension): - """Handle an enable request""" - enable_extension(extension, app_options=self.app_options) - raise gen.Return( - dict( - status="ok", - ) - ) - - @gen.coroutine - def disable(self, extension): - """Handle a disable request""" - disable_extension(extension, app_options=self.app_options) - raise gen.Return( - dict( - status="ok", + links.append(f'<{next_}>; rel="next"') + query_args["page"] = 1 + first = urlunparse( + ( + self.request.protocol, + self.request.host, + self.request.path, + "", + urlencode(query_args, doseq=True), + "", + ) ) - ) - - @gen.coroutine - def _get_pkg_info(self, name, data): - """Get information about a package""" - info = read_package(data["path"]) - - # Get latest version that is compatible with current lab: - outdated = yield self._get_outdated() - if outdated and name in outdated: - info["latest_version"] = outdated[name] - else: - # Fallback to indicating that current is latest - info["latest_version"] = info["version"] - - raise gen.Return(info) - - def _get_outdated(self): - """Get a Future to information from `npm/yarn outdated`. - - This will cache the results. To refresh the cache, set - self._outdated to None before calling. To bypass the cache, - call self._load_outdated directly. - """ - # Ensure self._outdated is a Future for data on outdated extensions - if self._outdated is None: - self._outdated = self._load_outdated() - # Return the Future - return self._outdated - - def refresh_outdated(self): - self._outdated = self._load_outdated() - return self._outdated - - @gen.coroutine - def _load_outdated(self): - """Get the latest compatible version""" - info = get_app_info(app_options=self.app_options) - names = tuple(info["extensions"].keys()) - data = yield self.executor.submit( - get_latest_compatible_package_versions, names, app_options=self.app_options - ) - raise gen.Return(data) - - @gen.coroutine - def _get_scheduled_uninstall_info(self, name): - """Get information about a package that is scheduled for uninstallation""" - target = os.path.join(self.app_dir, "staging", "node_modules", name, "package.json") - if os.path.exists(target): - with open(target) as fid: - raise gen.Return(json.load(fid)) - else: - raise gen.Return(None) + links.append(f'<{first}>; rel="first"') + self.set_header("Link", ", ".join(links)) - -class ExtensionHandler(ExtensionHandlerMixin, APIHandler): - def initialize(self, manager=None, name=None): - super(ExtensionHandler, self).initialize(name=name) - self.manager = manager + self.finish(json.dumps(list(map(dataclasses.asdict, extensions)))) @web.authenticated - @gen.coroutine - def get(self): - """GET query returns info on all installed extensions""" - if self.get_argument("refresh", False) == "1": - yield self.manager.refresh_outdated() - extensions = yield self.manager.list_extensions() - self.finish(json.dumps(extensions)) - - @web.authenticated - @gen.coroutine - def post(self): - """POST query performs an action on a specific extension""" + async def post(self): + """POST query performs an action on a specific extension + + Body arguments: + { + "cmd": Action to perform - ["install", "uninstall", "enable", "disable"] + "extension_name": Extension name + "extension_version": [optional] Extension version (used only for install action) + } + """ data = self.get_json_body() cmd = data["cmd"] name = data["extension_name"] + version = data.get("extension_version") if cmd not in ("install", "uninstall", "enable", "disable") or not name: raise web.HTTPError( - 422, "Could not process instruction %r with extension name %r" % (cmd, name) + 422, + f"Could not process instruction {cmd!r} with extension name {name!r}", ) - # TODO: Can we trust extension_name? Does it need sanitation? - # It comes from an authenticated session, but its name is - # ultimately from the NPM repository. ret_value = None try: if cmd == "install": - ret_value = yield self.manager.install(name) + ret_value = await self.manager.install(name, version) elif cmd == "uninstall": - ret_value = yield self.manager.uninstall(name) + ret_value = await self.manager.uninstall(name) elif cmd == "enable": - ret_value = yield self.manager.enable(name) + ret_value = await self.manager.enable(name) elif cmd == "disable": - ret_value = yield self.manager.disable(name) - except gen.Return as e: - ret_value = e.value + ret_value = await self.manager.disable(name) except Exception as e: - raise web.HTTPError(500, str(e)) + raise web.HTTPError(500, str(e)) from e - if ret_value is None: - self.set_status(200) + if ret_value.status == "error": + self.set_status(500) else: - self.finish(json.dumps(ret_value)) + self.set_status(201) + self.finish(json.dumps(dataclasses.asdict(ret_value))) # The path for lab extensions handler. diff --git a/jupyterlab/jlpmapp.py b/jupyterlab/jlpmapp.py index 8617c5be0484..425ce2dde51e 100644 --- a/jupyterlab/jlpmapp.py +++ b/jupyterlab/jlpmapp.py @@ -1,4 +1,3 @@ -# coding: utf-8 """A Jupyter-aware wrapper for the yarn package manager""" import os @@ -34,11 +33,11 @@ def execvp(cmd, argv): p.wait() sys.exit(p.returncode) else: - os.execvp(cmd, argv) + os.execvp(cmd, argv) # noqa S606 def main(argv=None): """Run node and return the result.""" # Make sure node is available. argv = argv or sys.argv[1:] - execvp("node", ["node", YARN_PATH] + argv) + execvp("node", ["node", YARN_PATH, *argv]) diff --git a/jupyterlab/labapp.py b/jupyterlab/labapp.py index 2242d17ed8c3..62a17f31c924 100644 --- a/jupyterlab/labapp.py +++ b/jupyterlab/labapp.py @@ -1,13 +1,12 @@ -# coding: utf-8 """A tornado based Jupyter lab server.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import dataclasses import json import os import sys -from os.path import join as pjoin from jupyter_core.application import JupyterApp, NoStart, base_aliases, base_flags from jupyter_server._version import version_info as jpserver_version_info @@ -20,7 +19,7 @@ WorkspaceImportApp, WorkspaceListApp, ) -from nbclassic.shim import NBClassicConfigShimMixin +from notebook_shim.shim import NotebookConfigShimMixin from traitlets import Bool, Instance, Type, Unicode, default from ._version import __version__ @@ -43,6 +42,8 @@ ) from .coreconfig import CoreConfig from .debuglog import DebugLogFileMixin +from .extensions import MANAGERS as EXT_MANAGERS +from .extensions.readonly import ReadOnlyExtensionManager from .handlers.announcements import ( CheckForUpdate, CheckForUpdateABC, @@ -53,11 +54,7 @@ ) from .handlers.build_handler import Builder, BuildHandler, build_path from .handlers.error_handler import ErrorHandler -from .handlers.extension_manager_handler import ( - ExtensionHandler, - ExtensionManager, - extensions_handler_path, -) +from .handlers.extension_manager_handler import ExtensionHandler, extensions_handler_path DEV_NOTE = """You're running JupyterLab from source. If you're working on the TypeScript sources of JupyterLab, try running @@ -84,7 +81,10 @@ build_flags = dict(base_flags) -build_flags["dev-build"] = ({"LabBuildApp": {"dev_build": True}}, "Build in development mode.") +build_flags["dev-build"] = ( + {"LabBuildApp": {"dev_build": True}}, + "Build in development mode.", +) build_flags["no-minimize"] = ( {"LabBuildApp": {"minimize": False}}, "Do not minimize a production build.", @@ -98,9 +98,9 @@ version = __version__ app_version = get_app_version() if version != app_version: - version = "%s (dev), %s (app)" % (__version__, app_version) + version = f"{__version__} (dev), {app_version} (app)" -buildFailureMsg = """Build failed. +build_failure_msg = """Build failed. Troubleshooting: If the build failed due to an out-of-memory error, you may be able to fix it by disabling the `dev_build` and/or `minimize` options. @@ -167,7 +167,9 @@ class LabBuildApp(JupyterApp, DebugLogFileMixin): ) minimize = Bool( - True, config=True, help="Whether to minimize a production build (defaults to True)." + True, + config=True, + help="Whether to minimize a production build (defaults to True).", ) pre_clean = Bool( @@ -200,7 +202,7 @@ def start(self): minimize=self.minimize, ) except Exception as e: - print(buildFailureMsg) + self.log.error(build_failure_msg) raise e @@ -214,8 +216,14 @@ def start(self): {"LabCleanApp": {"extensions": True}}, "Also delete /extensions.\n%s" % ext_warn_msg, ) -clean_flags["settings"] = ({"LabCleanApp": {"settings": True}}, "Also delete /settings") -clean_flags["static"] = ({"LabCleanApp": {"static": True}}, "Also delete /static") +clean_flags["settings"] = ( + {"LabCleanApp": {"settings": True}}, + "Also delete /settings", +) +clean_flags["static"] = ( + {"LabCleanApp": {"static": True}}, + "Also delete /static", +) clean_flags["all"] = ( {"LabCleanApp": {"all": True}}, "Delete the entire contents of the app directory.\n%s" % ext_warn_msg, @@ -227,7 +235,7 @@ class LabCleanAppOptions(AppOptions): settings = Bool(False) staging = Bool(True) static = Bool(False) - all = Bool(False) + all = Bool(False) # noqa class LabCleanApp(JupyterApp): @@ -255,7 +263,7 @@ class LabCleanApp(JupyterApp): static = Bool(False, config=True, help="Also delete /static") - all = Bool( + all = Bool( # noqa False, config=True, help="Delete the entire contents of the app directory.\n%s" % ext_warn_msg, @@ -327,7 +335,7 @@ class LabWorkspaceApp(JupyterApp): There are three sub-commands for export, import or listing of workspaces. This app should not otherwise do any work. """ - subcommands = dict() + subcommands = {} subcommands["export"] = ( LabWorkspaceExportApp, LabWorkspaceExportApp.description.splitlines()[0], @@ -344,7 +352,7 @@ class LabWorkspaceApp(JupyterApp): def start(self): try: super().start() - print("One of `export`, `import` or `list` must be specified.") + self.log.error("One of `export`, `import` or `list` must be specified.") self.exit(1) except NoStart: pass @@ -404,7 +412,7 @@ def _default_static_dir(self): ) -class LabApp(NBClassicConfigShimMixin, LabServerApp): +class LabApp(NotebookConfigShimMixin, LabServerApp): version = version name = "lab" @@ -451,11 +459,18 @@ class LabApp(NBClassicConfigShimMixin, LabServerApp): aliases["app-dir"] = "LabApp.app_dir" flags = flags - flags["core-mode"] = ({"LabApp": {"core_mode": True}}, "Start the app in core mode.") + flags["core-mode"] = ( + {"LabApp": {"core_mode": True}}, + "Start the app in core mode.", + ) flags["dev-mode"] = ( {"LabApp": {"dev_mode": True}}, "Start the app in dev mode for running from source.", ) + flags["skip-dev-build"] = ( + {"LabApp": {"skip_dev_build": True}}, + "Skip the initial install and JS build of the app in dev mode.", + ) flags["watch"] = ({"LabApp": {"watch": True}}, "Start the app in watch mode.") flags["splice-source"] = ( {"LabApp": {"splice_source": True}}, @@ -463,8 +478,7 @@ class LabApp(NBClassicConfigShimMixin, LabServerApp): ) flags["expose-app-in-browser"] = ( {"LabApp": {"expose_app_in_browser": True}}, - """Expose the global app instance to browser via window.jupyterapp. - It is also available via the deprecated window.jupyterlab name.""", + "Expose the global app instance to browser via window.jupyterapp.", ) flags["extensions-in-dev-mode"] = ( {"LabApp": {"extensions_in_dev_mode": True}}, @@ -472,25 +486,24 @@ class LabApp(NBClassicConfigShimMixin, LabServerApp): ) flags["collaborative"] = ( {"LabApp": {"collaborative": True}}, - "Whether to enable collaborative mode.", - ) - flags["future-skip-styles-for-disabled"] = ( - {"LabApp": {"future_skip_styles_for_disabled": True}}, - """Whether to skip loading styles for disabled prebuilt extensions. - This will be the default behavior starting with JupyterLab 4.0 - (and this flag will be removed).""", - ) + """To enable real-time collaboration, you must install the extension `jupyter_collaboration`. + You can install it using pip for example: - subcommands = dict( - build=(LabBuildApp, LabBuildApp.description.splitlines()[0]), - clean=(LabCleanApp, LabCleanApp.description.splitlines()[0]), - path=(LabPathApp, LabPathApp.description.splitlines()[0]), - paths=(LabPathApp, LabPathApp.description.splitlines()[0]), - workspace=(LabWorkspaceApp, LabWorkspaceApp.description.splitlines()[0]), - workspaces=(LabWorkspaceApp, LabWorkspaceApp.description.splitlines()[0]), - licenses=(LabLicensesApp, LabLicensesApp.description.splitlines()[0]), + python -m pip install jupyter_collaboration + + This flag is now deprecated and will be removed in JupyterLab v5.""", ) + subcommands = { + "build": (LabBuildApp, LabBuildApp.description.splitlines()[0]), + "clean": (LabCleanApp, LabCleanApp.description.splitlines()[0]), + "path": (LabPathApp, LabPathApp.description.splitlines()[0]), + "paths": (LabPathApp, LabPathApp.description.splitlines()[0]), + "workspace": (LabWorkspaceApp, LabWorkspaceApp.description.splitlines()[0]), + "workspaces": (LabWorkspaceApp, LabWorkspaceApp.description.splitlines()[0]), + "licenses": (LabLicensesApp, LabLicensesApp.description.splitlines()[0]), + } + default_url = Unicode("/lab", config=True, help="The default URL to redirect to from `/`") override_static_url = Unicode( @@ -498,7 +511,8 @@ class LabApp(NBClassicConfigShimMixin, LabServerApp): ) override_theme_url = Unicode( - config=True, help=("The override url for static lab theme assets, typically a CDN.") + config=True, + help=("The override url for static lab theme assets, typically a CDN."), ) app_dir = Unicode(None, config=True, help="The app directory to launch JupyterLab from.") @@ -540,25 +554,40 @@ class LabApp(NBClassicConfigShimMixin, LabServerApp): against published packages may not work correctly.""", ) + extension_manager = Unicode( + "pypi", + config=True, + help="""The extension manager factory to use. The default options are: + "readonly" for a manager without installation capability or "pypi" for + a manager using PyPi.org and pip to install extensions.""", + ) + watch = Bool(False, config=True, help="Whether to serve the app in watch mode") + skip_dev_build = Bool( + False, + config=True, + help="Whether to skip the initial install and JS build of the app in dev mode", + ) + splice_source = Bool(False, config=True, help="Splice source packages into app directory.") expose_app_in_browser = Bool( False, config=True, - help="Whether to expose the global app instance to browser via window.jupyterlab", + help="Whether to expose the global app instance to browser via window.jupyterapp", ) - future_skip_styles_for_disabled = Bool( + collaborative = Bool( False, config=True, - help="""Whether to skip loading styles for disabled prebuilt extensions. - This will be the default behavior starting with JupyterLab 4.0 - (and this flag will be removed).""", - ) + help="""To enable real-time collaboration, you must install the extension `jupyter_collaboration`. + You can install it using pip for example: - collaborative = Bool(False, config=True, help="Whether to enable collaborative mode.") + python -m pip install jupyter_collaboration + + This flag is now deprecated and will be removed in JupyterLab v5.""", + ) news_url = Unicode( "https://jupyterlab.github.io/assets/feed.xml", @@ -618,7 +647,7 @@ def _default_static_url_prefix(self): if self.override_static_url: return self.override_static_url else: - static_url = "/static/{name}/".format(name=self.name) + static_url = f"/static/{self.name}/" return ujoin(self.serverapp.base_url, static_url) @default("theme_url") @@ -638,11 +667,11 @@ def initialize_templates(self): self.log.info("Running JupyterLab in dev mode") if self.watch and self.core_mode: - self.log.warn("Cannot watch in core mode, did you mean --dev-mode?") + self.log.warning("Cannot watch in core mode, did you mean --dev-mode?") self.watch = False if self.core_mode and self.dev_mode: - self.log.warn("Conflicting modes, choosing dev_mode over core_mode") + self.log.warning("Conflicting modes, choosing dev_mode over core_mode") self.core_mode = False # Set the paths based on JupyterLab's mode. @@ -651,8 +680,18 @@ def initialize_templates(self): self.static_paths = [dev_static_dir] self.template_paths = [dev_static_dir] if not self.extensions_in_dev_mode: - self.labextensions_path = [] - self.extra_labextensions_path = [] + # Add an exception for @jupyterlab/galata-extension + galata_extension = pjoin(HERE, "galata") + self.labextensions_path = ( + [galata_extension] + if galata_extension in map(os.path.abspath, self.labextensions_path) + else [] + ) + self.extra_labextensions_path = ( + [galata_extension] + if galata_extension in map(os.path.abspath, self.extra_labextensions_path) + else [] + ) elif self.core_mode: dev_static_dir = ujoin(HERE, "static") self.static_paths = [dev_static_dir] @@ -663,11 +702,7 @@ def initialize_templates(self): self.static_paths = [self.static_dir] self.template_paths = [self.templates_dir] - def initialize_settings(self): - super().initialize_settings() - - def initialize_handlers(self): - + def initialize_handlers(self): # noqa handlers = [] # Set config for Jupyterlab @@ -678,9 +713,7 @@ def initialize_handlers(self): page_config["token"] = self.serverapp.token page_config["exposeAppInBrowser"] = self.expose_app_in_browser page_config["quitButton"] = self.serverapp.quit_button - page_config["collaborative"] = self.collaborative page_config["allow_hidden_files"] = self.serverapp.contents_manager.allow_hidden - page_config["futureSkipStylesForDisabled"] = self.future_skip_styles_for_disabled # Client-side code assumes notebookVersion is a JSON-encoded string page_config["notebookVersion"] = json.dumps(jpserver_version_info) @@ -704,7 +737,7 @@ def initialize_handlers(self): self.log.info(CORE_NOTE.strip()) ensure_core(self.log) elif self.dev_mode: - if not self.watch: + if not (self.watch or self.skip_dev_build): ensure_dev(self.log) self.log.info(DEV_NOTE) else: @@ -727,8 +760,60 @@ def initialize_handlers(self): self.cache_files = False if not self.core_mode and not errored: - ext_manager = ExtensionManager(app_options=build_handler_options) - ext_handler = (extensions_handler_path, ExtensionHandler, {"manager": ext_manager}) + # Add extension management handlers + provider = self.extension_manager + entry_point = EXT_MANAGERS.get(provider) + if entry_point is None: + self.log.error(f"Extension Manager: No manager defined for provider '{provider}'.") + raise NotImplementedError() + else: + self.log.info(f"Extension Manager is '{provider}'.") + manager_factory = entry_point.load() + config = self.settings.get("config", {}).get("LabServerApp", {}) + + blocked_extensions_uris = config.get("blocked_extensions_uris", "") + allowed_extensions_uris = config.get("allowed_extensions_uris", "") + + if (blocked_extensions_uris) and (allowed_extensions_uris): + self.log.error( + "Simultaneous LabServerApp.blocked_extensions_uris and LabServerApp.allowed_extensions_uris is not supported. Please define only one of those." + ) + import sys + + sys.exit(-1) + + listings_config = { + "blocked_extensions_uris": set( + filter(lambda uri: len(uri) > 0, blocked_extensions_uris.split(",")) + ), + "allowed_extensions_uris": set( + filter(lambda uri: len(uri) > 0, allowed_extensions_uris.split(",")) + ), + "listings_refresh_seconds": config.get("listings_refresh_seconds", 60 * 60), + "listings_tornado_options": config.get("listings_tornado_options", {}), + } + if len(listings_config["blocked_extensions_uris"]) or len( + listings_config["allowed_extensions_uris"] + ): + self.log.debug(f"Extension manager will be constrained by {listings_config}") + + try: + ext_manager = manager_factory(build_handler_options, listings_config, self) + metadata = dataclasses.asdict(ext_manager.metadata) + except Exception as err: + self.log.warning( + f"Failed to instantiate the extension manager {provider}. Falling back to read-only manager.", + exc_info=err, + ) + ext_manager = ReadOnlyExtensionManager(build_handler_options, listings_config, self) + metadata = dataclasses.asdict(ext_manager.metadata) + + page_config["extensionManager"] = metadata + ext_handler = ( + extensions_handler_path, + ExtensionHandler, + {"manager": ext_manager}, + ) handlers.append(ext_handler) # Add announcement handlers @@ -779,16 +864,21 @@ def initialize_handlers(self): def initialize(self, argv=None): """Subclass because the ExtensionApp.initialize() method does not take arguments""" super().initialize() - - if self.collaborative and jpserver_version_info < (2, 0, 0): - jpserver_version = ".".join(filter(lambda p: len(p) > 0, map(str, jpserver_version_info))) - self.log.critical(f"""To enable real-time collaboration, you must install Jupyter Server v2 (current version is {jpserver_version}). - + if self.collaborative: + try: + import jupyter_collaboration # noqa + except ImportError: + self.log.critical( + """ +To enable real-time collaboration, you must install the extension `jupyter_collaboration`. You can install it using pip for example: - python -m pip install "jupyter_server>=2.0.0" -""") - sys.exit(1) + python -m pip install jupyter_collaboration + +This flag is now deprecated and will be removed in JupyterLab v5. +""" + ) + sys.exit(1) # ----------------------------------------------------------------------------- diff --git a/jupyterlab/labextensions.py b/jupyterlab/labextensions.py index 9681607fc93d..5a1a82109ba9 100644 --- a/jupyterlab/labextensions.py +++ b/jupyterlab/labextensions.py @@ -1,4 +1,3 @@ -# coding: utf-8 """Jupyter LabExtension Entry Points.""" # Copyright (c) Jupyter Development Team. @@ -29,11 +28,7 @@ unlink_package, update_extension, ) -from .federated_labextensions import ( - build_labextension, - develop_labextension_py, - watch_labextension, -) +from .federated_labextensions import build_labextension, develop_labextension_py, watch_labextension from .labapp import LabApp flags = dict(base_flags) @@ -99,8 +94,6 @@ VERSION = get_app_version() -HERE = os.path.abspath(os.path.dirname(__file__)) - LABEXTENSION_COMMAND_WARNING = "Users should manage prebuilt extensions with package managers like pip and conda, and extension authors are encouraged to distribute their extensions as prebuilt packages" @@ -156,7 +149,8 @@ def _default_splice_source(self): def start(self): if self.app_dir and self.app_dir.startswith(HERE): - raise ValueError("Cannot run lab extension commands in core app") + msg = "Cannot run lab extension commands in core app" + raise ValueError(msg) with self.debug_logging(): ans = self.run_task() if ans and self.should_build: @@ -213,25 +207,23 @@ def run_task(self): pinned_versions = self.pin.split(",") self.extra_args = self.extra_args or [os.getcwd()] return any( - [ - install_extension( - arg, - # Pass in pinned alias if we have it - pin=pinned_versions[i] if i < len(pinned_versions) else None, - app_options=AppOptions( - app_dir=self.app_dir, - logger=self.log, - core_config=self.core_config, - labextensions_path=self.labextensions_path, - ), - ) - for i, arg in enumerate(self.extra_args) - ] + install_extension( + arg, + # Pass in pinned alias if we have it + pin=pinned_versions[i] if i < len(pinned_versions) else None, + app_options=AppOptions( + app_dir=self.app_dir, + logger=self.log, + core_config=self.core_config, + labextensions_path=self.labextensions_path, + ), + ) + for i, arg in enumerate(self.extra_args) ) class DevelopLabExtensionApp(BaseExtensionApp): - description = "Develop labextension" + description = "(developer) Develop labextension" flags = develop_flags user = Bool(False, config=True, help="Whether to do a user install") @@ -246,7 +238,7 @@ class DevelopLabExtensionApp(BaseExtensionApp): ) def run_task(self): - "Add config for this labextension" + """Add config for this labextension""" self.extra_args = self.extra_args or [os.getcwd()] for arg in self.extra_args: develop_labextension_py( @@ -261,7 +253,7 @@ def run_task(self): class BuildLabExtensionApp(BaseExtensionApp): - description = "Build labextension" + description = "(developer) Build labextension" static_url = Unicode("", config=True, help="Sets the url for static assets when building") @@ -295,7 +287,7 @@ def run_task(self): class WatchLabExtensionApp(BaseExtensionApp): - description = "Watch labextension" + description = "(developer) Watch labextension" development = Bool(True, config=True, help="Build in development mode") @@ -330,14 +322,16 @@ class UpdateLabExtensionApp(BaseExtensionApp): description = "Update labextension(s)" flags = update_flags - all = Bool(False, config=True, help="Whether to update all extensions") + all = Bool(False, config=True, help="Whether to update all extensions") # noqa def run_task(self): self.deprecation_warning( "Updating extensions with the jupyter labextension update command is now deprecated and will be removed in a future major version of JupyterLab." ) if not self.all and not self.extra_args: - self.log.warn("Specify an extension to update, or use --all to update all extensions") + self.log.warning( + "Specify an extension to update, or use --all to update all extensions" + ) return False app_options = AppOptions( app_dir=self.app_dir, @@ -347,7 +341,7 @@ def run_task(self): ) if self.all: return update_extension(all_=True, app_options=app_options) - return any([update_extension(name=arg, app_options=app_options) for arg in self.extra_args]) + return any(update_extension(name=arg, app_options=app_options) for arg in self.extra_args) class LinkLabExtensionApp(BaseExtensionApp): @@ -368,7 +362,7 @@ def run_task(self): labextensions_path=self.labextensions_path, core_config=self.core_config, ) - return any([link_package(arg, app_options=options) for arg in self.extra_args]) + return any(link_package(arg, app_options=options) for arg in self.extra_args) class UnlinkLabExtensionApp(BaseExtensionApp): @@ -382,14 +376,14 @@ def run_task(self): labextensions_path=self.labextensions_path, core_config=self.core_config, ) - return any([unlink_package(arg, app_options=options) for arg in self.extra_args]) + return any(unlink_package(arg, app_options=options) for arg in self.extra_args) class UninstallLabExtensionApp(BaseExtensionApp): description = "Uninstall labextension(s) by name" flags = uninstall_flags - all = Bool(False, config=True, help="Whether to uninstall all extensions") + all = Bool(False, config=True, help="Whether to uninstall all extensions") # noqa def run_task(self): self.deprecation_warning( @@ -404,10 +398,7 @@ def run_task(self): core_config=self.core_config, ) return any( - [ - uninstall_extension(arg, all_=self.all, app_options=options) - for arg in self.extra_args - ] + uninstall_extension(arg, all_=self.all, app_options=options) for arg in self.extra_args ) @@ -494,13 +485,13 @@ def run_task(self): self.exit(1) -_examples = """ +_EXAMPLES = """ jupyter labextension list # list all configured labextensions -jupyter labextension develop # develop a prebuilt labextension -jupyter labextension build # build a prebuilt labextension -jupyter labextension watch # watch a prebuilt labextension jupyter labextension install # install a labextension jupyter labextension uninstall # uninstall a labextension +jupyter labextension develop # (developer) develop a prebuilt labextension +jupyter labextension build # (developer) build a prebuilt labextension +jupyter labextension watch # (developer) watch a prebuilt labextension """ @@ -510,26 +501,26 @@ class LabExtensionApp(JupyterApp): name = "jupyter labextension" version = VERSION description = "Work with JupyterLab extensions" - examples = _examples - - subcommands = dict( - install=(InstallLabExtensionApp, "Install labextension(s)"), - develop=(DevelopLabExtensionApp, "Develop labextension(s)"), - build=(BuildLabExtensionApp, "Build labextension"), - watch=(WatchLabExtensionApp, "Watch labextension"), - update=(UpdateLabExtensionApp, "Update labextension(s)"), - uninstall=(UninstallLabExtensionApp, "Uninstall labextension(s)"), - list=(ListLabExtensionsApp, "List labextensions"), - link=(LinkLabExtensionApp, "Link labextension(s)"), - unlink=(UnlinkLabExtensionApp, "Unlink labextension(s)"), - enable=(EnableLabExtensionsApp, "Enable labextension(s)"), - disable=(DisableLabExtensionsApp, "Disable labextension(s)"), - check=(CheckLabExtensionsApp, "Check labextension(s)"), - ) + examples = _EXAMPLES + + subcommands = { + "install": (InstallLabExtensionApp, "Install labextension(s)"), + "update": (UpdateLabExtensionApp, "Update labextension(s)"), + "uninstall": (UninstallLabExtensionApp, "Uninstall labextension(s)"), + "list": (ListLabExtensionsApp, "List labextensions"), + "link": (LinkLabExtensionApp, "Link labextension(s)"), + "unlink": (UnlinkLabExtensionApp, "Unlink labextension(s)"), + "enable": (EnableLabExtensionsApp, "Enable labextension(s)"), + "disable": (DisableLabExtensionsApp, "Disable labextension(s)"), + "check": (CheckLabExtensionsApp, "Check labextension(s)"), + "develop": (DevelopLabExtensionApp, "(developer) Develop labextension(s)"), + "build": (BuildLabExtensionApp, "(developer) Build labextension"), + "watch": (WatchLabExtensionApp, "(developer) Watch labextension"), + } def start(self): """Perform the App's functions as configured""" - super(LabExtensionApp, self).start() + super().start() # The above should have called a subcommand and raised NoStart; if we # get here, it didn't, so we should self.log.info a message. diff --git a/jupyterlab/labhubapp.py b/jupyterlab/labhubapp.py index cbe1565fddf6..d8dc9d51df13 100644 --- a/jupyterlab/labhubapp.py +++ b/jupyterlab/labhubapp.py @@ -1,4 +1,3 @@ -# coding: utf-8 """A JupyterHub EntryPoint that defaults to use JupyterLab""" # Copyright (c) Jupyter Development Team. diff --git a/jupyterlab/node-version-check.js b/jupyterlab/node-version-check.js index ac858a211349..a8a5c445c80e 100644 --- a/jupyterlab/node-version-check.js +++ b/jupyterlab/node-version-check.js @@ -1,4 +1,8 @@ -#!/usr/bin/env node +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const pkg = require('./staging/package.json'); function parser(part) { diff --git a/jupyterlab/pytest_plugin.py b/jupyterlab/pytest_plugin.py index 3374c6f48123..4ca1b3aa925b 100644 --- a/jupyterlab/pytest_plugin.py +++ b/jupyterlab/pytest_plugin.py @@ -1,3 +1,6 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + import urllib.parse import pytest @@ -96,13 +99,14 @@ def labapp(jp_serverapp, make_lab_app): def fetch_long(http_server_client, jp_auth_header, jp_base_url): """fetch fixture that handles auth, base_url, and path""" - def client_fetch(*parts, headers={}, params={}, **kwargs): + def client_fetch(*parts, headers=None, params=None, **kwargs): # Handle URL strings path_url = url_escape(url_path_join(*parts), plus=False) path_url = url_path_join(jp_base_url, path_url) - params_url = urllib.parse.urlencode(params) + params_url = urllib.parse.urlencode(params or {}) url = path_url + "?" + params_url # Add auth keys to header + headers = headers or {} headers.update(jp_auth_header) # Make request. return http_server_client.fetch(url, headers=headers, request_timeout=250, **kwargs) diff --git a/jupyterlab/semver.py b/jupyterlab/semver.py index 941823e9ad45..c785152946f4 100644 --- a/jupyterlab/semver.py +++ b/jupyterlab/semver.py @@ -1,4 +1,6 @@ -# -*- coding:utf-8 -*- +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + # This file comes from https://github.com/podhmo/python-semver/blob/b42e9896e391e086b773fc621b23fa299d16b874/semver/__init__.py # # It is licensed under the following license: @@ -33,14 +35,10 @@ SEMVER_SPEC_VERSION = "2.0.0" -# Python 2/3 compatibility -try: - string_type = basestring -except NameError: - string_type = str +string_type = str -class _R(object): +class _R: def __init__(self, i): self.i = i @@ -327,10 +325,7 @@ def list_get(xs, i): def parse(version, loose): - if loose: - r = regexp[LOOSE] - else: - r = regexp[FULL] + r = regexp[LOOSE] if loose else regexp[FULL] m = r.search(version) if m: return semver(version, loose) @@ -354,7 +349,7 @@ def clean(version, loose): return None -NUMERIC = re.compile("^\d+$") +NUMERIC = re.compile(r"^\d+$") def semver(version, loose): @@ -364,7 +359,7 @@ def semver(version, loose): else: version = version.version elif not isinstance(version, string_type): # xxx: - raise ValueError("Invalid Version: {}".format(version)) + raise ValueError(f"Invalid Version: {version}") """ if (!(this instanceof SemVer)) @@ -376,7 +371,7 @@ def semver(version, loose): make_semver = semver -class SemVer(object): +class SemVer: def __init__(self, version, loose): logger.debug("SemVer %s, %s", version, loose) self.loose = loose @@ -385,7 +380,7 @@ def __init__(self, version, loose): m = regexp[LOOSE if loose else FULL].search(version.strip()) if not m: if not loose: - raise ValueError("Invalid Version: {}".format(version)) + raise ValueError(f"Invalid Version: {version}") m = regexp[RECOVERYVERSIONNAME].search(version.strip()) self.major = int(m.group(1)) if m.group(1) else 0 self.minor = int(m.group(2)) if m.group(2) else 0 @@ -394,7 +389,7 @@ def __init__(self, version, loose): self.prerelease = [] else: self.prerelease = [ - (int(id) if NUMERIC.search(id) else id) for id in m.group(3).split(".") + (int(id_) if NUMERIC.search(id_) else id_) for id_ in m.group(3).split(".") ] else: # these are actually numbers @@ -405,9 +400,8 @@ def __init__(self, version, loose): if not m.group(4): self.prerelease = [] else: - self.prerelease = [ - (int(id) if NUMERIC.search(id) else id) for id in m.group(4).split(".") + (int(id_) if NUMERIC.search(id_) else id_) for id_ in m.group(4).split(".") ] if m.group(5): self.build = m.group(5).split(".") @@ -416,14 +410,14 @@ def __init__(self, version, loose): self.format() # xxx: - def format(self): - self.version = "{}.{}.{}".format(self.major, self.minor, self.patch) + def format(self): # noqa + self.version = f"{self.major}.{self.minor}.{self.patch}" if len(self.prerelease) > 0: self.version += "-{}".format(".".join(str(v) for v in self.prerelease)) return self.version def __repr__(self): - return "".format(self) + return f"" def __str__(self): return self.version @@ -446,7 +440,7 @@ def compare_main(self, other): or compare_identifiers(str(self.patch), str(other.patch)) ) - def compare_pre(self, other): + def compare_pre(self, other): # noqa PLR0911 if not isinstance(other, SemVer): other = make_semver(other, self.loose) @@ -478,7 +472,7 @@ def compare_pre(self, other): else: return compare_identifiers(str(a), str(b)) - def inc(self, release, identifier=None): + def inc(self, release, identifier=None): # noqa PLR0915 logger.debug("inc release %s %s", self.prerelease, release) if release == "premajor": self.prerelease = [] @@ -556,7 +550,7 @@ def inc(self, release, identifier=None): else: self.prerelease = [identifier, 0] else: - raise ValueError("invalid increment argument: {}".format(release)) + raise ValueError(f"invalid increment argument: {release}") self.format() self.raw = self.version return self @@ -610,11 +604,11 @@ def make_key_function(loose): def key_function(version): v = make_semver(version, loose) key = (v.major, v.minor, v.patch) - if v.prerelease: + if v.prerelease: # noqa SIM108 key = key + tuple(v.prerelease) else: # NOT having a prerelease is > having one - key = key + (float("inf"),) + key = (*key, float("inf")) return key @@ -625,16 +619,16 @@ def key_function(version): full_key_function = make_key_function(True) -def sort(list, loose): +def sort(list_, loose): keyf = loose_key_function if loose else full_key_function - list.sort(key=keyf) - return list + list_.sort(key=keyf) + return list_ -def rsort(list, loose): +def rsort(list_, loose): keyf = loose_key_function if loose else full_key_function - list.sort(key=keyf, reverse=True) - return list + list_.sort(key=keyf, reverse=True) + return list_ def gt(a, b, loose): @@ -661,7 +655,7 @@ def lte(a, b, loose): return compare(a, b, loose) <= 0 -def cmp(a, op, b, loose): +def cmp(a, op, b, loose): # noqa PLR0911 logger.debug("cmp: %s", op) if op == "===": return a == b @@ -680,7 +674,7 @@ def cmp(a, op, b, loose): elif op == "<=": return lte(a, b, loose) else: - raise ValueError("Invalid operator: {}".format(op)) + raise ValueError(f"Invalid operator: {op}") def comparator(comp, loose): @@ -700,7 +694,7 @@ def comparator(comp, loose): ANY = object() -class Comparator(object): +class Comparator: semver = None def __init__(self, comp, loose): @@ -714,15 +708,12 @@ def __init__(self, comp, loose): self.value = self.operator + self.semver.version def parse(self, comp): - if self.loose: - r = regexp[COMPARATORLOOSE] - else: - r = regexp[COMPARATOR] + r = regexp[COMPARATORLOOSE] if self.loose else regexp[COMPARATOR] logger.debug("parse comp=%s", comp) m = r.search(comp) if m is None: - raise ValueError("Invalid comparator: {}".format(comp)) + raise ValueError(f"Invalid comparator: {comp}") self.operator = m.group(1) # if it literally is just '>' or '' then allow anything. @@ -732,7 +723,7 @@ def parse(self, comp): self.semver = semver(m.group(2), self.loose) def __repr__(self): - return ''.format(self) + return f'' def __str__(self): return self.value @@ -754,7 +745,7 @@ def make_range(range_, loose): return Range(range_, loose) -class Range(object): +class Range: def __init__(self, range_, loose): self.loose = loose # First, split based on boolean or || @@ -763,14 +754,14 @@ def __init__(self, range_, loose): self.set = [r for r in xs if r] if not len(self.set): - raise ValueError("Invalid SemVer Range: {}".format(range_)) + raise ValueError(f"Invalid SemVer Range: {range_}") self.format() def __repr__(self): - return ''.format(self.range) + return f'' - def format(self): + def format(self): # noqa self.range = "||".join( [" ".join(c.value for c in comps).strip() for comps in self.set] ).strip() @@ -784,10 +775,7 @@ def parse_range(self, range_): loose = self.loose logger.debug("range %s %s", range_, loose) # `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` - if loose: - hr = regexp[HYPHENRANGELOOSE] - else: - hr = regexp[HYPHENRANGE] + hr = regexp[HYPHENRANGELOOSE] if loose else regexp[HYPHENRANGE] range_ = hr.sub( hyphen_replace, @@ -806,16 +794,13 @@ def parse_range(self, range_): range_ = regexp[CARETTRIM].sub(caretTrimReplace, range_) # normalize spaces - range_ = " ".join(re.split("\s+", range_)) + range_ = " ".join(re.split(r"\s+", range_)) # At this point, the range is completely trimmed and # ready to be split into comparators. - if loose: - comp_re = regexp[COMPARATORLOOSE] - else: - comp_re = regexp[COMPARATOR] + comp_re = regexp[COMPARATORLOOSE] if loose else regexp[COMPARATOR] set_ = re.split( - "\s+", " ".join([parse_comparator(comp, loose) for comp in range_.split(" ")]) + r"\s+", " ".join([parse_comparator(comp, loose) for comp in range_.split(" ")]) ) if self.loose: # in loose mode, throw out any that are not valid comparators @@ -830,10 +815,7 @@ def test(self, version): if isinstance(version, string_type): version = make_semver(version, loose=self.loose) - for e in self.set: - if test_set(e, version): - return True - return False + return any(test_set(e, version) for e in self.set) # Mostly just for testing and legacy API reasons @@ -862,8 +844,8 @@ def parse_comparator(comp, loose): return comp -def is_x(id): - return id is None or id == "" or id.lower() == "x" or id == "*" +def is_x(id_): + return id_ is None or id_ == "" or id_.lower() == "x" or id_ == "*" # ~, ~> --> * (any, kinda silly) @@ -875,14 +857,11 @@ def is_x(id): def replace_tildes(comp, loose): - return " ".join([replace_tilde(c, loose) for c in re.split("\s+", comp.strip())]) + return " ".join([replace_tilde(c, loose) for c in re.split(r"\s+", comp.strip())]) def replace_tilde(comp, loose): - if loose: - r = regexp[TILDELOOSE] - else: - r = regexp[TILDE] + r = regexp[TILDELOOSE] if loose else regexp[TILDE] def repl(mob): _ = mob.group(0) @@ -916,16 +895,13 @@ def repl(mob): # ^1.2.3 --> >=1.2.3 <2.0.0 # ^1.2.0 --> >=1.2.0 <2.0.0 def replace_carets(comp, loose): - return " ".join([replace_caret(c, loose) for c in re.split("\s+", comp.strip())]) + return " ".join([replace_caret(c, loose) for c in re.split(r"\s+", comp.strip())]) def replace_caret(comp, loose): - if loose: - r = regexp[CARETLOOSE] - else: - r = regexp[CARET] + r = regexp[CARETLOOSE] if loose else regexp[CARET] - def repl(mob): + def repl(mob): # noqa PLR0911 m0 = mob.group(0) M, m, p, pr, _ = mob.groups() logger.debug("caret %s %s %s %s %s %s", comp, m0, M, m, p, pr) @@ -933,10 +909,10 @@ def repl(mob): if is_x(M): ret = "" elif is_x(m): - ret = ">=" + M + ".0.0 <" + str((int(M) + 1)) + ".0.0" + ret = ">=" + M + ".0.0 <" + str(int(M) + 1) + ".0.0" elif is_x(p): if M == "0": - ret = ">=" + M + "." + m + ".0 <" + M + "." + str((int(m) + 1)) + ".0" + ret = ">=" + M + "." + m + ".0 <" + M + "." + str(int(m) + 1) + ".0" else: ret = ">=" + M + "." + m + ".0 <" + str(int(M) + 1) + ".0.0" elif pr: @@ -978,7 +954,7 @@ def repl(mob): else: ret = ">=" + M + "." + m + "." + (p or "") + pr + " <" + str(int(M) + 1) + ".0.0" else: - if M == "0": + if M == "0": # PLR5501 if m == "0": ret = ( ">=" @@ -1005,7 +981,7 @@ def repl(mob): + " <" + M + "." - + str((int(m) + 1)) + + str(int(m) + 1) + ".0" ) else: @@ -1018,17 +994,14 @@ def repl(mob): def replace_xranges(comp, loose): logger.debug("replaceXRanges %s %s", comp, loose) - return " ".join([replace_xrange(c, loose) for c in re.split("\s+", comp.strip())]) + return " ".join([replace_xrange(c, loose) for c in re.split(r"\s+", comp.strip())]) def replace_xrange(comp, loose): comp = comp.strip() - if loose: - r = regexp[XRANGELOOSE] - else: - r = regexp[XRANGE] + r = regexp[XRANGELOOSE] if loose else regexp[XRANGE] - def repl(mob): + def repl(mob): # noqa PLR0911 ret = mob.group(0) gtlt, M, m, p, pr, _ = mob.groups() @@ -1044,7 +1017,7 @@ def repl(mob): logger.debug("xrange gtlt=%s any_x=%s", gtlt, any_x) if xM: - if gtlt == ">" or gtlt == "<": + if gtlt == ">" or gtlt == "<": # noqa SIM108 # nothing is allowed ret = "<0.0.0" else: @@ -1155,7 +1128,7 @@ def test_set(set_, version): def satisfies(version, range_, loose=False): try: range_ = make_range(range_, loose) - except Exception as e: + except Exception: return False return range_.test(version) @@ -1163,12 +1136,12 @@ def satisfies(version, range_, loose=False): def max_satisfying(versions, range_, loose=False): try: range_ob = make_range(range_, loose=loose) - except: + except Exception: return None max_ = None max_sv = None for v in versions: - if range_ob.test(v): # satisfies(v, range_, loose=loose) + if range_ob.test(v): # noqa # satisfies(v, range_, loose=loose) if max_ is None or max_sv.compare(v) == -1: # compare(max, v, true) max_ = v max_sv = make_semver(max_, loose=loose) @@ -1180,7 +1153,7 @@ def valid_range(range_, loose): # Return '*' instead of '' so that truthiness works. # This will throw if it's invalid anyway return make_range(range_, loose).range or "*" - except: + except Exception: return None @@ -1239,7 +1212,7 @@ def outside(version, range_, hilo, loose): # If the lowest version comparator has an operator and our version # is less than it then it isn't higher than the range - if (not low.operator or low.operator == comp) and ltefn(version, low.semver): + if (not low.operator or low.operator == comp) and ltefn(version, low.semver): # noqa SIM114 return False elif low.operator == ecomp and ltfn(version, low.semver): return False diff --git a/jupyterlab/serverextension.py b/jupyterlab/serverextension.py index 5d52d51e188d..3d20544d428e 100644 --- a/jupyterlab/serverextension.py +++ b/jupyterlab/serverextension.py @@ -1,4 +1,5 @@ -import sys +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. from jupyter_server.utils import url_path_join from tornado.web import RedirectHandler @@ -10,22 +11,6 @@ def load_jupyter_server_extension(serverapp): """Temporary server extension shim when using old notebook server. """ - serverapp.log.warning("Loading JupyterLab as a classic notebook (v6) extension.") - from jupyter_server._version import __version__ - try: - from packaging.version import parse, Version - if parse(__version__) >= Version('2.0.0'): - serverapp.log.critical( - f"You must use Jupyter Server v1 to load JupyterLab as notebook extension. You have v{__version__} installed.\nYou can fix this by executing:\n pip install -U \"jupyter-server<2.0.0\"" - ) - if serverapp.default_url == "/lab": - sys.exit(1) - else: - # Don't load JupyterLab when launching notebook - return - except Exception: # noqa - pass - extension = LabApp() extension.serverapp = serverapp extension.load_config_file() diff --git a/jupyterlab/staging/.yarnrc b/jupyterlab/staging/.yarnrc deleted file mode 100644 index d691d254e80d..000000000000 --- a/jupyterlab/staging/.yarnrc +++ /dev/null @@ -1,3 +0,0 @@ -yarn-path "./yarn.js" -ignore-optional true -network-timeout "300000" diff --git a/jupyterlab/staging/.yarnrc.yml b/jupyterlab/staging/.yarnrc.yml new file mode 100644 index 000000000000..3d59d5159723 --- /dev/null +++ b/jupyterlab/staging/.yarnrc.yml @@ -0,0 +1,6 @@ +enableImmutableInstalls: false +enableInlineBuilds: false +enableTelemetry: false +httpTimeout: 60000 +nodeLinker: node-modules +yarnPath: "./yarn.js" diff --git a/jupyterlab/staging/bootstrap.js b/jupyterlab/staging/bootstrap.js index 1b07e4b40677..9a5ae3eb3187 100644 --- a/jupyterlab/staging/bootstrap.js +++ b/jupyterlab/staging/bootstrap.js @@ -1,8 +1,8 @@ // This file is auto-generated from the corresponding file in /dev_mode -/*----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ // We copy some of the pageconfig parsing logic in @jupyterlab/coreutils // below, since this must run before any other files are loaded (including @@ -41,26 +41,6 @@ function getOption(name) { // eslint-disable-next-line no-undef __webpack_public_path__ = getOption('fullStaticUrl') + '/'; -// Promise.allSettled polyfill, until our supported browsers implement it -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled -if (Promise.allSettled === undefined) { - Promise.allSettled = promises => - Promise.all( - promises.map(promise => - promise.then( - value => ({ - status: 'fulfilled', - value - }), - reason => ({ - status: 'rejected', - reason - }) - ) - ) - ); -} - function loadScript(url) { return new Promise((resolve, reject) => { const newScript = document.createElement('script'); diff --git a/jupyterlab/staging/index.js b/jupyterlab/staging/index.js index 2e4baaeab105..0ec68c09fe9a 100644 --- a/jupyterlab/staging/index.js +++ b/jupyterlab/staging/index.js @@ -1,29 +1,11 @@ // This file is auto-generated from the corresponding file in /dev_mode -/*----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ import { PageConfig } from '@jupyterlab/coreutils'; -// Promise.allSettled polyfill, until our supported browsers implement it -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled -if (Promise.allSettled === undefined) { - Promise.allSettled = promises => - Promise.all( - promises.map(promise => - promise - .then(value => ({ - status: "fulfilled", - value, - }), reason => ({ - status: "rejected", - reason, - })) - ) - ); -} - import './style.js'; async function createModule(scope, module) { @@ -88,8 +70,6 @@ export async function main() { PageConfig.getOption('federated_extensions') ); - var futureSkipStylesForDisabled = (PageConfig.getOption('futureSkipStylesForDisabled') || '').toLowerCase() === 'true'; - const queuedFederated = []; extensions.forEach(data => { @@ -102,7 +82,7 @@ export async function main() { federatedMimeExtensionPromises.push(createModule(data.name, data.mimeExtension)); } - if (data.style && (!futureSkipStylesForDisabled || !PageConfig.Extension.isDisabled(data.name))) { + if (data.style && !PageConfig.Extension.isDisabled(data.name)) { federatedStylePromises.push(createModule(data.name, data.style)); } }); @@ -216,7 +196,6 @@ export async function main() { var devMode = (PageConfig.getOption('devMode') || '').toLowerCase() === 'true'; if (exposeAppInBrowser || devMode) { - window.jupyterlab = lab; window.jupyterapp = lab; } diff --git a/jupyterlab/staging/package.json b/jupyterlab/staging/package.json index f5bef8e6a56d..86b9d9d9e45a 100644 --- a/jupyterlab/staging/package.json +++ b/jupyterlab/staging/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/application-top", - "version": "3.6.6", + "version": "4.0.8", "private": true, "license": "BSD-3-Clause", "scripts": { @@ -8,223 +8,222 @@ "build:dev": "npm run build", "build:prod": "webpack --config webpack.prod.config.js", "build:prod:minimize": "webpack --config webpack.prod.minimize.config.js", + "build:prod:minimize:report": "npm run build:prod:minimize:stats && webpack-bundle-analyzer --no-open --mode static --report static/webpack-bundle-analyzer.html stats.json static", + "build:prod:minimize:stats": "webpack --profile --config webpack.prod.minimize.config.js --json > stats.json", "build:prod:release": "webpack --config webpack.prod.release.config.js", - "build:prod:stats": "webpack --profile --config webpack.prod.minimize.config.js --json > stats.json", "build:stats": "webpack --profile --json > stats.json", "clean": "rimraf build", "prepublishOnly": "npm run build", "watch": "webpack --watch" }, "resolutions": { - "@jupyter/ydoc": "~0.2.4", - "@jupyterlab/application": "~3.6.6", - "@jupyterlab/application-extension": "~3.6.6", - "@jupyterlab/apputils": "~3.6.6", - "@jupyterlab/apputils-extension": "~3.6.6", - "@jupyterlab/attachments": "~3.6.6", - "@jupyterlab/cell-toolbar": "~3.6.6", - "@jupyterlab/cell-toolbar-extension": "~3.6.6", - "@jupyterlab/cells": "~3.6.6", - "@jupyterlab/celltags": "~3.6.6", - "@jupyterlab/celltags-extension": "~3.6.6", - "@jupyterlab/codeeditor": "~3.6.6", - "@jupyterlab/codemirror": "~3.6.6", - "@jupyterlab/codemirror-extension": "~3.6.6", - "@jupyterlab/collaboration": "~3.6.6", - "@jupyterlab/collaboration-extension": "~3.6.6", - "@jupyterlab/completer": "~3.6.6", - "@jupyterlab/completer-extension": "~3.6.6", - "@jupyterlab/console": "~3.6.6", - "@jupyterlab/console-extension": "~3.6.6", - "@jupyterlab/coreutils": "~5.6.6", - "@jupyterlab/csvviewer": "~3.6.6", - "@jupyterlab/csvviewer-extension": "~3.6.6", - "@jupyterlab/debugger": "~3.6.6", - "@jupyterlab/debugger-extension": "~3.6.6", - "@jupyterlab/docmanager": "~3.6.6", - "@jupyterlab/docmanager-extension": "~3.6.6", - "@jupyterlab/docprovider": "~3.6.6", - "@jupyterlab/docprovider-extension": "~3.6.6", - "@jupyterlab/docregistry": "~3.6.6", - "@jupyterlab/documentsearch": "~3.6.6", - "@jupyterlab/documentsearch-extension": "~3.6.6", - "@jupyterlab/extensionmanager": "~3.6.6", - "@jupyterlab/extensionmanager-extension": "~3.6.6", - "@jupyterlab/filebrowser": "~3.6.6", - "@jupyterlab/filebrowser-extension": "~3.6.6", - "@jupyterlab/fileeditor": "~3.6.6", - "@jupyterlab/fileeditor-extension": "~3.6.6", - "@jupyterlab/help-extension": "~3.6.6", - "@jupyterlab/htmlviewer": "~3.6.6", - "@jupyterlab/htmlviewer-extension": "~3.6.6", - "@jupyterlab/hub-extension": "~3.6.6", - "@jupyterlab/imageviewer": "~3.6.6", - "@jupyterlab/imageviewer-extension": "~3.6.6", - "@jupyterlab/inspector": "~3.6.6", - "@jupyterlab/inspector-extension": "~3.6.6", - "@jupyterlab/javascript-extension": "~3.6.6", - "@jupyterlab/json-extension": "~3.6.6", - "@jupyterlab/launcher": "~3.6.6", - "@jupyterlab/launcher-extension": "~3.6.6", - "@jupyterlab/logconsole": "~3.6.6", - "@jupyterlab/logconsole-extension": "~3.6.6", - "@jupyterlab/mainmenu": "~3.6.6", - "@jupyterlab/mainmenu-extension": "~3.6.6", - "@jupyterlab/markdownviewer": "~3.6.6", - "@jupyterlab/markdownviewer-extension": "~3.6.6", - "@jupyterlab/mathjax2": "~3.6.6", - "@jupyterlab/mathjax2-extension": "~3.6.6", - "@jupyterlab/metapackage": "~3.6.6", - "@jupyterlab/nbconvert-css": "~3.6.6", - "@jupyterlab/nbformat": "~3.6.6", - "@jupyterlab/notebook": "~3.6.6", - "@jupyterlab/notebook-extension": "~3.6.6", - "@jupyterlab/observables": "~4.6.6", - "@jupyterlab/outputarea": "~3.6.6", - "@jupyterlab/pdf-extension": "~3.6.6", - "@jupyterlab/property-inspector": "~3.6.6", - "@jupyterlab/rendermime": "~3.6.6", - "@jupyterlab/rendermime-extension": "~3.6.6", - "@jupyterlab/rendermime-interfaces": "~3.6.6", - "@jupyterlab/running": "~3.6.6", - "@jupyterlab/running-extension": "~3.6.6", - "@jupyterlab/services": "../../packages/services", - "@jupyterlab/settingeditor": "~3.6.6", - "@jupyterlab/settingeditor-extension": "~3.6.6", - "@jupyterlab/settingregistry": "~3.6.6", - "@jupyterlab/shared-models": "~3.6.6", - "@jupyterlab/shortcuts-extension": "~3.6.6", - "@jupyterlab/statedb": "~3.6.6", - "@jupyterlab/statusbar": "~3.6.6", - "@jupyterlab/statusbar-extension": "~3.6.6", - "@jupyterlab/terminal": "~3.6.6", - "@jupyterlab/terminal-extension": "~3.6.6", - "@jupyterlab/theme-dark-extension": "~3.6.6", - "@jupyterlab/theme-light-extension": "~3.6.6", - "@jupyterlab/toc": "~5.6.6", - "@jupyterlab/toc-extension": "~5.6.6", - "@jupyterlab/tooltip": "~3.6.6", - "@jupyterlab/tooltip-extension": "~3.6.6", - "@jupyterlab/translation": "~3.6.6", - "@jupyterlab/translation-extension": "~3.6.6", - "@jupyterlab/ui-components": "~3.6.6", - "@jupyterlab/ui-components-extension": "~3.6.6", - "@jupyterlab/vdom": "~3.6.6", - "@jupyterlab/vdom-extension": "~3.6.6", - "@jupyterlab/vega5-extension": "~3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/application": "^1.31.4", - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/domutils": "^1.8.0", - "@lumino/dragdrop": "^1.13.0", - "@lumino/messaging": "^1.10.0", - "@lumino/properties": "^1.8.0", - "@lumino/signaling": "^1.10.0", - "@lumino/virtualdom": "^1.14.0", - "@lumino/widgets": "^1.37.2", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "yjs": "^13.5.17" + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.2.0", + "@codemirror/view": "^6.9.6", + "@jupyter/ydoc": "~1.0.2", + "@jupyterlab/application": "~4.0.8", + "@jupyterlab/application-extension": "~4.0.8", + "@jupyterlab/apputils": "~4.1.8", + "@jupyterlab/apputils-extension": "~4.0.8", + "@jupyterlab/attachments": "~4.0.8", + "@jupyterlab/cell-toolbar": "~4.0.8", + "@jupyterlab/cell-toolbar-extension": "~4.0.8", + "@jupyterlab/cells": "~4.0.8", + "@jupyterlab/celltags-extension": "~4.0.8", + "@jupyterlab/codeeditor": "~4.0.8", + "@jupyterlab/codemirror": "~4.0.8", + "@jupyterlab/codemirror-extension": "~4.0.8", + "@jupyterlab/completer": "~4.0.8", + "@jupyterlab/completer-extension": "~4.0.8", + "@jupyterlab/console": "~4.0.8", + "@jupyterlab/console-extension": "~4.0.8", + "@jupyterlab/coreutils": "~6.0.8", + "@jupyterlab/csvviewer": "~4.0.8", + "@jupyterlab/csvviewer-extension": "~4.0.8", + "@jupyterlab/debugger": "~4.0.8", + "@jupyterlab/debugger-extension": "~4.0.8", + "@jupyterlab/docmanager": "~4.0.8", + "@jupyterlab/docmanager-extension": "~4.0.8", + "@jupyterlab/docregistry": "~4.0.8", + "@jupyterlab/documentsearch": "~4.0.8", + "@jupyterlab/documentsearch-extension": "~4.0.8", + "@jupyterlab/extensionmanager": "~4.0.8", + "@jupyterlab/extensionmanager-extension": "~4.0.8", + "@jupyterlab/filebrowser": "~4.0.8", + "@jupyterlab/filebrowser-extension": "~4.0.8", + "@jupyterlab/fileeditor": "~4.0.8", + "@jupyterlab/fileeditor-extension": "~4.0.8", + "@jupyterlab/help-extension": "~4.0.8", + "@jupyterlab/htmlviewer": "~4.0.8", + "@jupyterlab/htmlviewer-extension": "~4.0.8", + "@jupyterlab/hub-extension": "~4.0.8", + "@jupyterlab/imageviewer": "~4.0.8", + "@jupyterlab/imageviewer-extension": "~4.0.8", + "@jupyterlab/inspector": "~4.0.8", + "@jupyterlab/inspector-extension": "~4.0.8", + "@jupyterlab/javascript-extension": "~4.0.8", + "@jupyterlab/json-extension": "~4.0.8", + "@jupyterlab/launcher": "~4.0.8", + "@jupyterlab/launcher-extension": "~4.0.8", + "@jupyterlab/logconsole": "~4.0.8", + "@jupyterlab/logconsole-extension": "~4.0.8", + "@jupyterlab/lsp": "~4.0.8", + "@jupyterlab/lsp-extension": "~4.0.8", + "@jupyterlab/mainmenu": "~4.0.8", + "@jupyterlab/mainmenu-extension": "~4.0.8", + "@jupyterlab/markdownviewer": "~4.0.8", + "@jupyterlab/markdownviewer-extension": "~4.0.8", + "@jupyterlab/markedparser-extension": "~4.0.8", + "@jupyterlab/mathjax-extension": "~4.0.8", + "@jupyterlab/metadataform": "~4.0.8", + "@jupyterlab/metadataform-extension": "~4.0.8", + "@jupyterlab/metapackage": "~4.0.8", + "@jupyterlab/nbconvert-css": "~4.0.8", + "@jupyterlab/nbformat": "~4.0.8", + "@jupyterlab/notebook": "~4.0.8", + "@jupyterlab/notebook-extension": "~4.0.8", + "@jupyterlab/observables": "~5.0.8", + "@jupyterlab/outputarea": "~4.0.8", + "@jupyterlab/pdf-extension": "~4.0.8", + "@jupyterlab/property-inspector": "~4.0.8", + "@jupyterlab/rendermime": "~4.0.8", + "@jupyterlab/rendermime-extension": "~4.0.8", + "@jupyterlab/rendermime-interfaces": "~3.8.8", + "@jupyterlab/running": "~4.0.8", + "@jupyterlab/running-extension": "~4.0.8", + "@jupyterlab/services": "~7.0.8", + "@jupyterlab/settingeditor": "~4.0.8", + "@jupyterlab/settingeditor-extension": "~4.0.8", + "@jupyterlab/settingregistry": "~4.0.8", + "@jupyterlab/shortcuts-extension": "~4.0.8", + "@jupyterlab/statedb": "~4.0.8", + "@jupyterlab/statusbar": "~4.0.8", + "@jupyterlab/statusbar-extension": "~4.0.8", + "@jupyterlab/terminal": "~4.0.8", + "@jupyterlab/terminal-extension": "~4.0.8", + "@jupyterlab/theme-dark-extension": "~4.0.8", + "@jupyterlab/theme-light-extension": "~4.0.8", + "@jupyterlab/toc": "~6.0.8", + "@jupyterlab/toc-extension": "~6.0.8", + "@jupyterlab/tooltip": "~4.0.8", + "@jupyterlab/tooltip-extension": "~4.0.8", + "@jupyterlab/translation": "~4.0.8", + "@jupyterlab/translation-extension": "~4.0.8", + "@jupyterlab/ui-components": "~4.0.8", + "@jupyterlab/ui-components-extension": "~4.0.8", + "@jupyterlab/vega5-extension": "~4.0.8", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lumino/algorithm": "^2.0.0", + "@lumino/application": "^2.0.1", + "@lumino/commands": "^2.0.1", + "@lumino/coreutils": "^2.0.0", + "@lumino/datagrid": "^2.0.1", + "@lumino/disposable": "^2.0.0", + "@lumino/domutils": "^2.0.0", + "@lumino/dragdrop": "^2.0.0", + "@lumino/keyboard": "^2.0.0", + "@lumino/messaging": "^2.0.0", + "@lumino/polling": "^2.0.0", + "@lumino/properties": "^2.0.0", + "@lumino/signaling": "^2.0.0", + "@lumino/virtualdom": "^2.0.0", + "@lumino/widgets": "^2.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "yjs": "^13.5.40" }, "dependencies": { - "@jupyterlab/application": "~3.6.6", - "@jupyterlab/application-extension": "~3.6.6", - "@jupyterlab/apputils-extension": "~3.6.6", - "@jupyterlab/cell-toolbar-extension": "~3.6.6", - "@jupyterlab/celltags-extension": "~3.6.6", - "@jupyterlab/codemirror-extension": "~3.6.6", - "@jupyterlab/collaboration-extension": "~3.6.6", - "@jupyterlab/completer-extension": "~3.6.6", - "@jupyterlab/console-extension": "~3.6.6", - "@jupyterlab/coreutils": "~5.6.6", - "@jupyterlab/csvviewer-extension": "~3.6.6", - "@jupyterlab/debugger-extension": "~3.6.6", - "@jupyterlab/docmanager-extension": "~3.6.6", - "@jupyterlab/docprovider-extension": "~3.6.6", - "@jupyterlab/documentsearch-extension": "~3.6.6", - "@jupyterlab/extensionmanager-extension": "~3.6.6", - "@jupyterlab/filebrowser-extension": "~3.6.6", - "@jupyterlab/fileeditor-extension": "~3.6.6", - "@jupyterlab/help-extension": "~3.6.6", - "@jupyterlab/htmlviewer-extension": "~3.6.6", - "@jupyterlab/hub-extension": "~3.6.6", - "@jupyterlab/imageviewer-extension": "~3.6.6", - "@jupyterlab/inspector-extension": "~3.6.6", - "@jupyterlab/javascript-extension": "~3.6.6", - "@jupyterlab/json-extension": "~3.6.6", - "@jupyterlab/launcher-extension": "~3.6.6", - "@jupyterlab/logconsole-extension": "~3.6.6", - "@jupyterlab/mainmenu-extension": "~3.6.6", - "@jupyterlab/markdownviewer-extension": "~3.6.6", - "@jupyterlab/mathjax2-extension": "~3.6.6", - "@jupyterlab/notebook-extension": "~3.6.6", - "@jupyterlab/pdf-extension": "~3.6.6", - "@jupyterlab/rendermime-extension": "~3.6.6", - "@jupyterlab/running-extension": "~3.6.6", - "@jupyterlab/settingeditor-extension": "~3.6.6", - "@jupyterlab/shortcuts-extension": "~3.6.6", - "@jupyterlab/statusbar-extension": "~3.6.6", - "@jupyterlab/terminal-extension": "~3.6.6", - "@jupyterlab/theme-dark-extension": "~3.6.6", - "@jupyterlab/theme-light-extension": "~3.6.6", - "@jupyterlab/toc-extension": "~5.6.6", - "@jupyterlab/tooltip-extension": "~3.6.6", - "@jupyterlab/translation-extension": "~3.6.6", - "@jupyterlab/ui-components-extension": "~3.6.6", - "@jupyterlab/vdom-extension": "~3.6.6", - "@jupyterlab/vega5-extension": "~3.6.6" + "@jupyterlab/application": "~4.0.8", + "@jupyterlab/application-extension": "~4.0.8", + "@jupyterlab/apputils-extension": "~4.0.8", + "@jupyterlab/cell-toolbar-extension": "~4.0.8", + "@jupyterlab/celltags-extension": "~4.0.8", + "@jupyterlab/codemirror-extension": "~4.0.8", + "@jupyterlab/completer-extension": "~4.0.8", + "@jupyterlab/console-extension": "~4.0.8", + "@jupyterlab/coreutils": "~6.0.8", + "@jupyterlab/csvviewer-extension": "~4.0.8", + "@jupyterlab/debugger-extension": "~4.0.8", + "@jupyterlab/docmanager-extension": "~4.0.8", + "@jupyterlab/documentsearch-extension": "~4.0.8", + "@jupyterlab/extensionmanager-extension": "~4.0.8", + "@jupyterlab/filebrowser-extension": "~4.0.8", + "@jupyterlab/fileeditor-extension": "~4.0.8", + "@jupyterlab/help-extension": "~4.0.8", + "@jupyterlab/htmlviewer-extension": "~4.0.8", + "@jupyterlab/hub-extension": "~4.0.8", + "@jupyterlab/imageviewer-extension": "~4.0.8", + "@jupyterlab/inspector-extension": "~4.0.8", + "@jupyterlab/javascript-extension": "~4.0.8", + "@jupyterlab/json-extension": "~4.0.8", + "@jupyterlab/launcher-extension": "~4.0.8", + "@jupyterlab/logconsole-extension": "~4.0.8", + "@jupyterlab/lsp-extension": "~4.0.8", + "@jupyterlab/mainmenu-extension": "~4.0.8", + "@jupyterlab/markdownviewer-extension": "~4.0.8", + "@jupyterlab/markedparser-extension": "~4.0.8", + "@jupyterlab/mathjax-extension": "~4.0.8", + "@jupyterlab/metadataform-extension": "~4.0.8", + "@jupyterlab/notebook-extension": "~4.0.8", + "@jupyterlab/pdf-extension": "~4.0.8", + "@jupyterlab/rendermime-extension": "~4.0.8", + "@jupyterlab/running-extension": "~4.0.8", + "@jupyterlab/settingeditor-extension": "~4.0.8", + "@jupyterlab/shortcuts-extension": "~4.0.8", + "@jupyterlab/statusbar-extension": "~4.0.8", + "@jupyterlab/terminal-extension": "~4.0.8", + "@jupyterlab/theme-dark-extension": "~4.0.8", + "@jupyterlab/theme-light-extension": "~4.0.8", + "@jupyterlab/toc-extension": "~6.0.8", + "@jupyterlab/tooltip-extension": "~4.0.8", + "@jupyterlab/translation-extension": "~4.0.8", + "@jupyterlab/ui-components-extension": "~4.0.8", + "@jupyterlab/vega5-extension": "~4.0.8" }, "devDependencies": { - "@jupyterlab/builder": "^3.6.6", - "@jupyterlab/buildutils": "^3.6.6", + "@jupyterlab/builder": "^4.0.8", + "@jupyterlab/buildutils": "^4.0.8", "chokidar": "^3.4.0", - "css-loader": "^5.0.1", + "css-loader": "^6.7.1", "duplicate-package-checker-webpack-plugin": "^3.0.0", - "file-loader": "~6.0.0", - "fs-extra": "^9.0.1", + "fs-extra": "^10.1.0", "glob": "~7.1.6", "handlebars": "^4.5.3", "html-loader": "~1.3.0", - "html-webpack-plugin": "^5.0.0-beta.6", - "license-webpack-plugin": "^2.3.14", - "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", + "html-webpack-plugin": "^5.5.0", + "license-webpack-plugin": "^4.0.2", + "mini-css-extract-plugin": "^2.7.0", + "mini-svg-data-uri": "^1.4.4", "rimraf": "~3.0.0", - "sort-package-json": "~1.44.0", + "sort-package-json": "~1.53.1", "source-map-loader": "~1.0.2", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "terser-webpack-plugin": "^4.1.0", - "url-loader": "~4.1.0", - "webpack": "^5.41.1", - "webpack-bundle-analyzer": "^3.6.0", - "webpack-cli": "^4.1.0", - "webpack-merge": "^5.1.2", + "style-loader": "~3.3.1", + "terser-webpack-plugin": "^5.3.7", + "webpack": "^5.76.1", + "webpack-bundle-analyzer": "^4.8.0", + "webpack-cli": "^5.0.1", + "webpack-merge": "^5.8.0", "whatwg-fetch": "^3.0.0", - "worker-loader": "^3.0.2", - "yarn-deduplicate": "^2.1.1" + "worker-loader": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" }, "jupyterlab": { "name": "JupyterLab", - "version": "3.6.6", + "version": "4.0.8", "extensions": { "@jupyterlab/application-extension": "", "@jupyterlab/apputils-extension": "", "@jupyterlab/cell-toolbar-extension": "", "@jupyterlab/celltags-extension": "", "@jupyterlab/codemirror-extension": "", - "@jupyterlab/collaboration-extension": "", "@jupyterlab/completer-extension": "", "@jupyterlab/console-extension": "", "@jupyterlab/csvviewer-extension": "", "@jupyterlab/debugger-extension": "", "@jupyterlab/docmanager-extension": "", - "@jupyterlab/docprovider-extension": "", "@jupyterlab/documentsearch-extension": "", "@jupyterlab/extensionmanager-extension": "", "@jupyterlab/filebrowser-extension": "", @@ -236,9 +235,12 @@ "@jupyterlab/inspector-extension": "", "@jupyterlab/launcher-extension": "", "@jupyterlab/logconsole-extension": "", + "@jupyterlab/lsp-extension": "", "@jupyterlab/mainmenu-extension": "", "@jupyterlab/markdownviewer-extension": "", - "@jupyterlab/mathjax2-extension": "", + "@jupyterlab/markedparser-extension": "", + "@jupyterlab/mathjax-extension": "", + "@jupyterlab/metadataform-extension": "", "@jupyterlab/notebook-extension": "", "@jupyterlab/rendermime-extension": "", "@jupyterlab/running-extension": "", @@ -251,8 +253,7 @@ "@jupyterlab/toc-extension": "", "@jupyterlab/tooltip-extension": "", "@jupyterlab/translation-extension": "", - "@jupyterlab/ui-components-extension": "", - "@jupyterlab/vdom-extension": "" + "@jupyterlab/ui-components-extension": "" }, "mimeExtensions": { "@jupyterlab/javascript-extension": "", @@ -260,40 +261,42 @@ "@jupyterlab/pdf-extension": "", "@jupyterlab/vega5-extension": "" }, - "externalExtensions": {}, "buildDir": "./build", "outputDir": "..", "singletonPackages": [ + "@codemirror/language", + "@codemirror/state", + "@codemirror/view", "@jupyter/ydoc", "@jupyterlab/application", "@jupyterlab/apputils", "@jupyterlab/cell-toolbar", "@jupyterlab/codeeditor", "@jupyterlab/codemirror", - "@jupyterlab/collaboration", "@jupyterlab/completer", "@jupyterlab/console", "@jupyterlab/coreutils", "@jupyterlab/debugger", "@jupyterlab/docmanager", - "@jupyterlab/docprovider", "@jupyterlab/documentsearch", "@jupyterlab/extensionmanager", "@jupyterlab/filebrowser", "@jupyterlab/fileeditor", + "@jupyterlab/htmlviewer", "@jupyterlab/imageviewer", "@jupyterlab/inspector", "@jupyterlab/launcher", "@jupyterlab/logconsole", + "@jupyterlab/lsp", "@jupyterlab/mainmenu", "@jupyterlab/markdownviewer", + "@jupyterlab/metadataform", "@jupyterlab/notebook", "@jupyterlab/rendermime", "@jupyterlab/rendermime-interfaces", "@jupyterlab/services", "@jupyterlab/settingeditor", "@jupyterlab/settingregistry", - "@jupyterlab/shared-models", "@jupyterlab/statedb", "@jupyterlab/statusbar", "@jupyterlab/terminal", @@ -301,14 +304,19 @@ "@jupyterlab/tooltip", "@jupyterlab/translation", "@jupyterlab/ui-components", + "@lezer/common", + "@lezer/highlight", "@lumino/algorithm", "@lumino/application", "@lumino/commands", "@lumino/coreutils", + "@lumino/datagrid", "@lumino/disposable", "@lumino/domutils", "@lumino/dragdrop", + "@lumino/keyboard", "@lumino/messaging", + "@lumino/polling", "@lumino/properties", "@lumino/signaling", "@lumino/virtualdom", diff --git a/jupyterlab/staging/templates/403.html b/jupyterlab/staging/templates/403.html index 315515710e72..34a495a1a308 100644 --- a/jupyterlab/staging/templates/403.html +++ b/jupyterlab/staging/templates/403.html @@ -1,3 +1,8 @@ + + diff --git a/jupyterlab/staging/templates/partial.html b/jupyterlab/staging/templates/partial.html index a3f368eaea74..3c44af54c52b 100644 --- a/jupyterlab/staging/templates/partial.html +++ b/jupyterlab/staging/templates/partial.html @@ -1,3 +1,8 @@ + + {# Copy so we do not modify the page_config with updates. #} {% set page_config_full = page_config.copy() %} diff --git a/jupyterlab/staging/templates/template.html b/jupyterlab/staging/templates/template.html index 167557d4fdda..6d17d790004d 100644 --- a/jupyterlab/staging/templates/template.html +++ b/jupyterlab/staging/templates/template.html @@ -1,3 +1,8 @@ + + diff --git a/jupyterlab/staging/webpack.config.js b/jupyterlab/staging/webpack.config.js index ec58eec6986d..d93406758d8b 100644 --- a/jupyterlab/staging/webpack.config.js +++ b/jupyterlab/staging/webpack.config.js @@ -1,8 +1,8 @@ // This file is auto-generated from the corresponding file in /dev_mode -/* ----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ const path = require('path'); const fs = require('fs-extra'); @@ -10,8 +10,8 @@ const Handlebars = require('handlebars'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); const merge = require('webpack-merge').default; -const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') - .BundleAnalyzerPlugin; +const BundleAnalyzerPlugin = + require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base'); const { ModuleFederationPlugin } = webpack.container; @@ -21,21 +21,7 @@ const packageData = require('./package.json'); // Handle the extensions. const jlab = packageData.jupyterlab; -const { extensions, mimeExtensions, externalExtensions } = jlab; - -// Add external extensions to the extensions/mimeExtensions data as -// appropriate -for (const pkg in externalExtensions) { - const { - jupyterlab: { extension, mimeExtension } - } = require(`${pkg}/package.json`); - if (extension !== undefined) { - extensions[pkg] = extension === true ? '' : extension; - } - if (mimeExtension !== undefined) { - mimeExtensions[pkg] = mimeExtension === true ? '' : mimeExtension; - } -} +const { extensions, mimeExtensions } = jlab; // Deduplicated list of extension package names. const extensionPackages = [ @@ -300,15 +286,14 @@ module.exports = [ output: { path: path.resolve(buildDir), publicPath: '{{page_config.fullStaticUrl}}/', - filename: '[name].[contenthash].js', - hashFunction: 'sha256' + filename: '[name].[contenthash].js' }, optimization: { splitChunks: { chunks: 'all', cacheGroups: { jlab_core: { - test: /[\\/]node_modules[\\/]@(jupyterlab|lumino)[\\/]/, + test: /[\\/]node_modules[\\/]@(jupyterlab|lumino(?!\/datagrid))[\\/]/, name: 'jlab_core' } } @@ -325,7 +310,7 @@ module.exports = [ ] }, devtool: 'inline-source-map', - externals: ['node-fetch', 'ws'], + externals: ['ws'], plugins }) ].concat(extensionAssetConfig); diff --git a/jupyterlab/staging/webpack.prod.config.js b/jupyterlab/staging/webpack.prod.config.js index 49813391fc58..bb8c9b33cf57 100644 --- a/jupyterlab/staging/webpack.prod.config.js +++ b/jupyterlab/staging/webpack.prod.config.js @@ -1,4 +1,9 @@ // This file is auto-generated from the corresponding file in /dev_mode +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const merge = require('webpack-merge').default; const config = require('./webpack.config'); const WPPlugin = require('@jupyterlab/builder').WPPlugin; diff --git a/jupyterlab/staging/webpack.prod.minimize.config.js b/jupyterlab/staging/webpack.prod.minimize.config.js index c8d45a70338a..80bd2b5ad81a 100644 --- a/jupyterlab/staging/webpack.prod.minimize.config.js +++ b/jupyterlab/staging/webpack.prod.minimize.config.js @@ -1,4 +1,9 @@ // This file is auto-generated from the corresponding file in /dev_mode +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const TerserPlugin = require('terser-webpack-plugin'); const merge = require('webpack-merge').default; const WPPlugin = require('@jupyterlab/builder').WPPlugin; @@ -17,7 +22,6 @@ config[0] = merge(config[0], { minimizer: [ new TerserPlugin({ parallel: true, - sourceMap: true, terserOptions: { compress: false, ecma: 6, @@ -27,8 +31,7 @@ config[0] = merge(config[0], { comments: false }, safari10: true - }, - cache: process.platform !== 'win32' + } }) ] }, diff --git a/jupyterlab/staging/webpack.prod.release.config.js b/jupyterlab/staging/webpack.prod.release.config.js index 54f6a3834a59..060d39a835a4 100644 --- a/jupyterlab/staging/webpack.prod.release.config.js +++ b/jupyterlab/staging/webpack.prod.release.config.js @@ -1,4 +1,9 @@ // This file is auto-generated from the corresponding file in /dev_mode +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const merge = require('webpack-merge').default; const config = require('./webpack.prod.minimize.config'); diff --git a/jupyterlab/staging/yarn.js b/jupyterlab/staging/yarn.js old mode 100644 new mode 100755 index cc7214faac0c..093e64a9fe46 --- a/jupyterlab/staging/yarn.js +++ b/jupyterlab/staging/yarn.js @@ -1,147315 +1,873 @@ #!/usr/bin/env node -module.exports = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 549); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = require("path"); - -/***/ }), -/* 1 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = __extends; -/* unused harmony export __assign */ -/* unused harmony export __rest */ -/* unused harmony export __decorate */ -/* unused harmony export __param */ -/* unused harmony export __metadata */ -/* unused harmony export __awaiter */ -/* unused harmony export __generator */ -/* unused harmony export __exportStar */ -/* unused harmony export __values */ -/* unused harmony export __read */ -/* unused harmony export __spread */ -/* unused harmony export __await */ -/* unused harmony export __asyncGenerator */ -/* unused harmony export __asyncDelegator */ -/* unused harmony export __asyncValues */ -/* unused harmony export __makeTemplateObject */ -/* unused harmony export __importStar */ -/* unused harmony export __importDefault */ -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ -/* global Reflect, Promise */ - -var extendStatics = function(d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); -}; - -function __extends(d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -} - -var __assign = function() { - __assign = Object.assign || function __assign(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; - } - return t; - } - return __assign.apply(this, arguments); -} - -function __rest(s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) - t[p[i]] = s[p[i]]; - return t; -} - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -} - -function __param(paramIndex, decorator) { - return function (target, key) { decorator(target, key, paramIndex); } -} - -function __metadata(metadataKey, metadataValue) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); -} - -function __awaiter(thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -} - -function __generator(thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -} - -function __exportStar(m, exports) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; -} - -function __values(o) { - var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; - if (m) return m.call(o); - return { - next: function () { - if (o && i >= o.length) o = void 0; - return { value: o && o[i++], done: !o }; - } - }; -} - -function __read(o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); - } - catch (error) { e = { error: error }; } - finally { - try { - if (r && !r.done && (m = i["return"])) m.call(i); - } - finally { if (e) throw e.error; } - } - return ar; -} - -function __spread() { - for (var ar = [], i = 0; i < arguments.length; i++) - ar = ar.concat(__read(arguments[i])); - return ar; -} - -function __await(v) { - return this instanceof __await ? (this.v = v, this) : new __await(v); -} - -function __asyncGenerator(thisArg, _arguments, generator) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var g = generator.apply(thisArg, _arguments || []), i, q = []; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; - function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } - function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } - function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } - function fulfill(value) { resume("next", value); } - function reject(value) { resume("throw", value); } - function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } -} - -function __asyncDelegator(o) { - var i, p; - return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } -} - -function __asyncValues(o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } -} - -function __makeTemplateObject(cooked, raw) { - if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } - return cooked; -}; - -function __importStar(mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; - result.default = mod; - return result; -} - -function __importDefault(mod) { - return (mod && mod.__esModule) ? mod : { default: mod }; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.__esModule = true; - -var _promise = __webpack_require__(227); - -var _promise2 = _interopRequireDefault(_promise); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = function (fn) { - return function () { - var gen = fn.apply(this, arguments); - return new _promise2.default(function (resolve, reject) { - function step(key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error) { - reject(error); - return; - } - - if (info.done) { - resolve(value); - } else { - return _promise2.default.resolve(value).then(function (value) { - step("next", value); - }, function (err) { - step("throw", err); - }); - } - } - - return step("next"); - }); - }; -}; - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -module.exports = require("util"); - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getFirstSuitableFolder = exports.readFirstAvailableStream = exports.makeTempDir = exports.hardlinksWork = exports.writeFilePreservingEol = exports.getFileSizeOnDisk = exports.walk = exports.symlink = exports.find = exports.readJsonAndFile = exports.readJson = exports.readFileAny = exports.hardlinkBulk = exports.copyBulk = exports.unlink = exports.glob = exports.link = exports.chmod = exports.lstat = exports.exists = exports.mkdirp = exports.stat = exports.access = exports.rename = exports.readdir = exports.realpath = exports.readlink = exports.writeFile = exports.open = exports.readFileBuffer = exports.lockQueue = exports.constants = undefined; - -var _asyncToGenerator2; - -function _load_asyncToGenerator() { - return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); -} - -let buildActionsForCopy = (() => { - var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { - - // - let build = (() => { - var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { - const src = data.src, - dest = data.dest, - type = data.type; - - const onFresh = data.onFresh || noop; - const onDone = data.onDone || noop; - - // TODO https://github.com/yarnpkg/yarn/issues/3751 - // related to bundled dependencies handling - if (files.has(dest.toLowerCase())) { - reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`); - } else { - files.add(dest.toLowerCase()); - } - - if (type === 'symlink') { - yield mkdirp((_path || _load_path()).default.dirname(dest)); - onFresh(); - actions.symlink.push({ - dest, - linkname: src - }); - onDone(); - return; - } - - if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { - // ignored file - return; - } - - const srcStat = yield lstat(src); - let srcFiles; - - if (srcStat.isDirectory()) { - srcFiles = yield readdir(src); - } - - let destStat; - try { - // try accessing the destination - destStat = yield lstat(dest); - } catch (e) { - // proceed if destination doesn't exist, otherwise error - if (e.code !== 'ENOENT') { - throw e; - } - } - - // if destination exists - if (destStat) { - const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); - const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); - const bothFiles = srcStat.isFile() && destStat.isFile(); - - // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving - // us modes that aren't valid. investigate this, it's generally safe to proceed. - - /* if (srcStat.mode !== destStat.mode) { - try { - await access(dest, srcStat.mode); - } catch (err) {} - } */ - - if (bothFiles && artifactFiles.has(dest)) { - // this file gets changed during build, likely by a custom install script. Don't bother checking it. - onDone(); - reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); - return; - } - - if (bothFiles && srcStat.size === destStat.size && (0, (_fsNormalized || _load_fsNormalized()).fileDatesEqual)(srcStat.mtime, destStat.mtime)) { - // we can safely assume this is the same file - onDone(); - reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime)); - return; - } - - if (bothSymlinks) { - const srcReallink = yield readlink(src); - if (srcReallink === (yield readlink(dest))) { - // if both symlinks are the same then we can continue on - onDone(); - reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); - return; - } - } - - if (bothFolders) { - // mark files that aren't in this folder as possibly extraneous - const destFiles = yield readdir(dest); - invariant(srcFiles, 'src files not initialised'); - - for (var _iterator4 = destFiles, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { - var _ref6; - - if (_isArray4) { - if (_i4 >= _iterator4.length) break; - _ref6 = _iterator4[_i4++]; - } else { - _i4 = _iterator4.next(); - if (_i4.done) break; - _ref6 = _i4.value; - } - - const file = _ref6; - - if (srcFiles.indexOf(file) < 0) { - const loc = (_path || _load_path()).default.join(dest, file); - possibleExtraneous.add(loc); - - if ((yield lstat(loc)).isDirectory()) { - for (var _iterator5 = yield readdir(loc), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { - var _ref7; - - if (_isArray5) { - if (_i5 >= _iterator5.length) break; - _ref7 = _iterator5[_i5++]; - } else { - _i5 = _iterator5.next(); - if (_i5.done) break; - _ref7 = _i5.value; - } - - const file = _ref7; - - possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); - } - } - } - } - } - } - - if (destStat && destStat.isSymbolicLink()) { - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); - destStat = null; - } - - if (srcStat.isSymbolicLink()) { - onFresh(); - const linkname = yield readlink(src); - actions.symlink.push({ - dest, - linkname - }); - onDone(); - } else if (srcStat.isDirectory()) { - if (!destStat) { - reporter.verbose(reporter.lang('verboseFileFolder', dest)); - yield mkdirp(dest); - } - - const destParts = dest.split((_path || _load_path()).default.sep); - while (destParts.length) { - files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); - destParts.pop(); - } - - // push all files to queue - invariant(srcFiles, 'src files not initialised'); - let remaining = srcFiles.length; - if (!remaining) { - onDone(); - } - for (var _iterator6 = srcFiles, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { - var _ref8; - - if (_isArray6) { - if (_i6 >= _iterator6.length) break; - _ref8 = _iterator6[_i6++]; - } else { - _i6 = _iterator6.next(); - if (_i6.done) break; - _ref8 = _i6.value; - } - - const file = _ref8; - - queue.push({ - dest: (_path || _load_path()).default.join(dest, file), - onFresh, - onDone: function (_onDone) { - function onDone() { - return _onDone.apply(this, arguments); - } - - onDone.toString = function () { - return _onDone.toString(); - }; - - return onDone; - }(function () { - if (--remaining === 0) { - onDone(); - } - }), - src: (_path || _load_path()).default.join(src, file) - }); - } - } else if (srcStat.isFile()) { - onFresh(); - actions.file.push({ - src, - dest, - atime: srcStat.atime, - mtime: srcStat.mtime, - mode: srcStat.mode - }); - onDone(); - } else { - throw new Error(`unsure how to copy this: ${src}`); - } - }); - - return function build(_x5) { - return _ref5.apply(this, arguments); - }; - })(); - - const artifactFiles = new Set(events.artifactFiles || []); - const files = new Set(); - - // initialise events - for (var _iterator = queue, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref2; - - if (_isArray) { - if (_i >= _iterator.length) break; - _ref2 = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref2 = _i.value; - } - - const item = _ref2; - - const onDone = item.onDone; - item.onDone = function () { - events.onProgress(item.dest); - if (onDone) { - onDone(); - } - }; - } - events.onStart(queue.length); - - // start building actions - const actions = { - file: [], - symlink: [], - link: [] - }; - - // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items - // at a time due to the requirement to push items onto the queue - while (queue.length) { - const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); - yield Promise.all(items.map(build)); - } - - // simulate the existence of some files to prevent considering them extraneous - for (var _iterator2 = artifactFiles, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { - var _ref3; - - if (_isArray2) { - if (_i2 >= _iterator2.length) break; - _ref3 = _iterator2[_i2++]; - } else { - _i2 = _iterator2.next(); - if (_i2.done) break; - _ref3 = _i2.value; - } - - const file = _ref3; - - if (possibleExtraneous.has(file)) { - reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); - possibleExtraneous.delete(file); - } - } - - for (var _iterator3 = possibleExtraneous, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { - var _ref4; - - if (_isArray3) { - if (_i3 >= _iterator3.length) break; - _ref4 = _iterator3[_i3++]; - } else { - _i3 = _iterator3.next(); - if (_i3.done) break; - _ref4 = _i3.value; - } - - const loc = _ref4; - - if (files.has(loc.toLowerCase())) { - possibleExtraneous.delete(loc); - } - } - - return actions; - }); - - return function buildActionsForCopy(_x, _x2, _x3, _x4) { - return _ref.apply(this, arguments); - }; -})(); - -let buildActionsForHardlink = (() => { - var _ref9 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { - - // - let build = (() => { - var _ref13 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { - const src = data.src, - dest = data.dest; - - const onFresh = data.onFresh || noop; - const onDone = data.onDone || noop; - if (files.has(dest.toLowerCase())) { - // Fixes issue https://github.com/yarnpkg/yarn/issues/2734 - // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1, - // package-linker passes that modules A1 and B1 need to be hardlinked, - // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case - // an exception. - onDone(); - return; - } - files.add(dest.toLowerCase()); - - if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { - // ignored file - return; - } - - const srcStat = yield lstat(src); - let srcFiles; - - if (srcStat.isDirectory()) { - srcFiles = yield readdir(src); - } - - const destExists = yield exists(dest); - if (destExists) { - const destStat = yield lstat(dest); - - const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); - const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); - const bothFiles = srcStat.isFile() && destStat.isFile(); - - if (srcStat.mode !== destStat.mode) { - try { - yield access(dest, srcStat.mode); - } catch (err) { - // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving - // us modes that aren't valid. investigate this, it's generally safe to proceed. - reporter.verbose(err); - } - } - - if (bothFiles && artifactFiles.has(dest)) { - // this file gets changed during build, likely by a custom install script. Don't bother checking it. - onDone(); - reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); - return; - } - - // correct hardlink - if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) { - onDone(); - reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino)); - return; - } - - if (bothSymlinks) { - const srcReallink = yield readlink(src); - if (srcReallink === (yield readlink(dest))) { - // if both symlinks are the same then we can continue on - onDone(); - reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); - return; - } - } - - if (bothFolders) { - // mark files that aren't in this folder as possibly extraneous - const destFiles = yield readdir(dest); - invariant(srcFiles, 'src files not initialised'); - - for (var _iterator10 = destFiles, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { - var _ref14; - - if (_isArray10) { - if (_i10 >= _iterator10.length) break; - _ref14 = _iterator10[_i10++]; - } else { - _i10 = _iterator10.next(); - if (_i10.done) break; - _ref14 = _i10.value; - } - - const file = _ref14; - - if (srcFiles.indexOf(file) < 0) { - const loc = (_path || _load_path()).default.join(dest, file); - possibleExtraneous.add(loc); - - if ((yield lstat(loc)).isDirectory()) { - for (var _iterator11 = yield readdir(loc), _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { - var _ref15; - - if (_isArray11) { - if (_i11 >= _iterator11.length) break; - _ref15 = _iterator11[_i11++]; - } else { - _i11 = _iterator11.next(); - if (_i11.done) break; - _ref15 = _i11.value; - } - - const file = _ref15; - - possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); - } - } - } - } - } - } - - if (srcStat.isSymbolicLink()) { - onFresh(); - const linkname = yield readlink(src); - actions.symlink.push({ - dest, - linkname - }); - onDone(); - } else if (srcStat.isDirectory()) { - reporter.verbose(reporter.lang('verboseFileFolder', dest)); - yield mkdirp(dest); - - const destParts = dest.split((_path || _load_path()).default.sep); - while (destParts.length) { - files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); - destParts.pop(); - } - - // push all files to queue - invariant(srcFiles, 'src files not initialised'); - let remaining = srcFiles.length; - if (!remaining) { - onDone(); - } - for (var _iterator12 = srcFiles, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { - var _ref16; - - if (_isArray12) { - if (_i12 >= _iterator12.length) break; - _ref16 = _iterator12[_i12++]; - } else { - _i12 = _iterator12.next(); - if (_i12.done) break; - _ref16 = _i12.value; - } - - const file = _ref16; - - queue.push({ - onFresh, - src: (_path || _load_path()).default.join(src, file), - dest: (_path || _load_path()).default.join(dest, file), - onDone: function (_onDone2) { - function onDone() { - return _onDone2.apply(this, arguments); - } - - onDone.toString = function () { - return _onDone2.toString(); - }; - - return onDone; - }(function () { - if (--remaining === 0) { - onDone(); - } - }) - }); - } - } else if (srcStat.isFile()) { - onFresh(); - actions.link.push({ - src, - dest, - removeDest: destExists - }); - onDone(); - } else { - throw new Error(`unsure how to copy this: ${src}`); - } - }); - - return function build(_x10) { - return _ref13.apply(this, arguments); - }; - })(); - - const artifactFiles = new Set(events.artifactFiles || []); - const files = new Set(); - - // initialise events - for (var _iterator7 = queue, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { - var _ref10; - - if (_isArray7) { - if (_i7 >= _iterator7.length) break; - _ref10 = _iterator7[_i7++]; - } else { - _i7 = _iterator7.next(); - if (_i7.done) break; - _ref10 = _i7.value; - } - - const item = _ref10; - - const onDone = item.onDone || noop; - item.onDone = function () { - events.onProgress(item.dest); - onDone(); - }; - } - events.onStart(queue.length); - - // start building actions - const actions = { - file: [], - symlink: [], - link: [] - }; - - // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items - // at a time due to the requirement to push items onto the queue - while (queue.length) { - const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); - yield Promise.all(items.map(build)); - } - - // simulate the existence of some files to prevent considering them extraneous - for (var _iterator8 = artifactFiles, _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { - var _ref11; - - if (_isArray8) { - if (_i8 >= _iterator8.length) break; - _ref11 = _iterator8[_i8++]; - } else { - _i8 = _iterator8.next(); - if (_i8.done) break; - _ref11 = _i8.value; - } - - const file = _ref11; - - if (possibleExtraneous.has(file)) { - reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); - possibleExtraneous.delete(file); - } - } - - for (var _iterator9 = possibleExtraneous, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { - var _ref12; - - if (_isArray9) { - if (_i9 >= _iterator9.length) break; - _ref12 = _iterator9[_i9++]; - } else { - _i9 = _iterator9.next(); - if (_i9.done) break; - _ref12 = _i9.value; - } - - const loc = _ref12; - - if (files.has(loc.toLowerCase())) { - possibleExtraneous.delete(loc); - } - } - - return actions; - }); - - return function buildActionsForHardlink(_x6, _x7, _x8, _x9) { - return _ref9.apply(this, arguments); - }; -})(); - -let copyBulk = exports.copyBulk = (() => { - var _ref17 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { - const events = { - onStart: _events && _events.onStart || noop, - onProgress: _events && _events.onProgress || noop, - possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), - ignoreBasenames: _events && _events.ignoreBasenames || [], - artifactFiles: _events && _events.artifactFiles || [] - }; - - const actions = yield buildActionsForCopy(queue, events, events.possibleExtraneous, reporter); - events.onStart(actions.file.length + actions.symlink.length + actions.link.length); - - const fileActions = actions.file; - - const currentlyWriting = new Map(); - - yield (_promise || _load_promise()).queue(fileActions, (() => { - var _ref18 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { - let writePromise; - while (writePromise = currentlyWriting.get(data.dest)) { - yield writePromise; - } - - reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest)); - const copier = (0, (_fsNormalized || _load_fsNormalized()).copyFile)(data, function () { - return currentlyWriting.delete(data.dest); - }); - currentlyWriting.set(data.dest, copier); - events.onProgress(data.dest); - return copier; - }); - - return function (_x14) { - return _ref18.apply(this, arguments); - }; - })(), CONCURRENT_QUEUE_ITEMS); - - // we need to copy symlinks last as they could reference files we were copying - const symlinkActions = actions.symlink; - yield (_promise || _load_promise()).queue(symlinkActions, function (data) { - const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); - reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); - return symlink(linkname, data.dest); - }); - }); - - return function copyBulk(_x11, _x12, _x13) { - return _ref17.apply(this, arguments); - }; -})(); - -let hardlinkBulk = exports.hardlinkBulk = (() => { - var _ref19 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { - const events = { - onStart: _events && _events.onStart || noop, - onProgress: _events && _events.onProgress || noop, - possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), - artifactFiles: _events && _events.artifactFiles || [], - ignoreBasenames: [] - }; - - const actions = yield buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter); - events.onStart(actions.file.length + actions.symlink.length + actions.link.length); - - const fileActions = actions.link; - - yield (_promise || _load_promise()).queue(fileActions, (() => { - var _ref20 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { - reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest)); - if (data.removeDest) { - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(data.dest); - } - yield link(data.src, data.dest); - }); - - return function (_x18) { - return _ref20.apply(this, arguments); - }; - })(), CONCURRENT_QUEUE_ITEMS); - - // we need to copy symlinks last as they could reference files we were copying - const symlinkActions = actions.symlink; - yield (_promise || _load_promise()).queue(symlinkActions, function (data) { - const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); - reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); - return symlink(linkname, data.dest); - }); - }); - - return function hardlinkBulk(_x15, _x16, _x17) { - return _ref19.apply(this, arguments); - }; -})(); - -let readFileAny = exports.readFileAny = (() => { - var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (files) { - for (var _iterator13 = files, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { - var _ref22; - - if (_isArray13) { - if (_i13 >= _iterator13.length) break; - _ref22 = _iterator13[_i13++]; - } else { - _i13 = _iterator13.next(); - if (_i13.done) break; - _ref22 = _i13.value; - } - - const file = _ref22; - - if (yield exists(file)) { - return readFile(file); - } - } - return null; - }); - - return function readFileAny(_x19) { - return _ref21.apply(this, arguments); - }; -})(); - -let readJson = exports.readJson = (() => { - var _ref23 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { - return (yield readJsonAndFile(loc)).object; - }); - - return function readJson(_x20) { - return _ref23.apply(this, arguments); - }; -})(); - -let readJsonAndFile = exports.readJsonAndFile = (() => { - var _ref24 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { - const file = yield readFile(loc); - try { - return { - object: (0, (_map || _load_map()).default)(JSON.parse(stripBOM(file))), - content: file - }; - } catch (err) { - err.message = `${loc}: ${err.message}`; - throw err; - } - }); - - return function readJsonAndFile(_x21) { - return _ref24.apply(this, arguments); - }; -})(); - -let find = exports.find = (() => { - var _ref25 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (filename, dir) { - const parts = dir.split((_path || _load_path()).default.sep); - - while (parts.length) { - const loc = parts.concat(filename).join((_path || _load_path()).default.sep); - - if (yield exists(loc)) { - return loc; - } else { - parts.pop(); - } - } - - return false; - }); - - return function find(_x22, _x23) { - return _ref25.apply(this, arguments); - }; -})(); - -let symlink = exports.symlink = (() => { - var _ref26 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (src, dest) { - if (process.platform !== 'win32') { - // use relative paths otherwise which will be retained if the directory is moved - src = (_path || _load_path()).default.relative((_path || _load_path()).default.dirname(dest), src); - // When path.relative returns an empty string for the current directory, we should instead use - // '.', which is a valid fs.symlink target. - src = src || '.'; - } - - try { - const stats = yield lstat(dest); - if (stats.isSymbolicLink()) { - const resolved = dest; - if (resolved === src) { - return; - } - } - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; - } - } - - // We use rimraf for unlink which never throws an ENOENT on missing target - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); - - if (process.platform === 'win32') { - // use directory junctions if possible on win32, this requires absolute paths - yield fsSymlink(src, dest, 'junction'); - } else { - yield fsSymlink(src, dest); - } - }); - - return function symlink(_x24, _x25) { - return _ref26.apply(this, arguments); - }; -})(); - -let walk = exports.walk = (() => { - var _ref27 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir, relativeDir, ignoreBasenames = new Set()) { - let files = []; - - let filenames = yield readdir(dir); - if (ignoreBasenames.size) { - filenames = filenames.filter(function (name) { - return !ignoreBasenames.has(name); - }); - } - - for (var _iterator14 = filenames, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { - var _ref28; - - if (_isArray14) { - if (_i14 >= _iterator14.length) break; - _ref28 = _iterator14[_i14++]; - } else { - _i14 = _iterator14.next(); - if (_i14.done) break; - _ref28 = _i14.value; - } - - const name = _ref28; - - const relative = relativeDir ? (_path || _load_path()).default.join(relativeDir, name) : name; - const loc = (_path || _load_path()).default.join(dir, name); - const stat = yield lstat(loc); - - files.push({ - relative, - basename: name, - absolute: loc, - mtime: +stat.mtime - }); - - if (stat.isDirectory()) { - files = files.concat((yield walk(loc, relative, ignoreBasenames))); - } - } - - return files; - }); - - return function walk(_x26, _x27) { - return _ref27.apply(this, arguments); - }; -})(); - -let getFileSizeOnDisk = exports.getFileSizeOnDisk = (() => { - var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { - const stat = yield lstat(loc); - const size = stat.size, - blockSize = stat.blksize; - - - return Math.ceil(size / blockSize) * blockSize; - }); - - return function getFileSizeOnDisk(_x28) { - return _ref29.apply(this, arguments); - }; -})(); - -let getEolFromFile = (() => { - var _ref30 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path) { - if (!(yield exists(path))) { - return undefined; - } - - const buffer = yield readFileBuffer(path); - - for (let i = 0; i < buffer.length; ++i) { - if (buffer[i] === cr) { - return '\r\n'; - } - if (buffer[i] === lf) { - return '\n'; - } - } - return undefined; - }); - - return function getEolFromFile(_x29) { - return _ref30.apply(this, arguments); - }; -})(); - -let writeFilePreservingEol = exports.writeFilePreservingEol = (() => { - var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path, data) { - const eol = (yield getEolFromFile(path)) || (_os || _load_os()).default.EOL; - if (eol !== '\n') { - data = data.replace(/\n/g, eol); - } - yield writeFile(path, data); - }); - - return function writeFilePreservingEol(_x30, _x31) { - return _ref31.apply(this, arguments); - }; -})(); - -let hardlinksWork = exports.hardlinksWork = (() => { - var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir) { - const filename = 'test-file' + Math.random(); - const file = (_path || _load_path()).default.join(dir, filename); - const fileLink = (_path || _load_path()).default.join(dir, filename + '-link'); - try { - yield writeFile(file, 'test'); - yield link(file, fileLink); - } catch (err) { - return false; - } finally { - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(file); - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(fileLink); - } - return true; - }); - - return function hardlinksWork(_x32) { - return _ref32.apply(this, arguments); - }; -})(); - -// not a strict polyfill for Node's fs.mkdtemp - - -let makeTempDir = exports.makeTempDir = (() => { - var _ref33 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (prefix) { - const dir = (_path || _load_path()).default.join((_os || _load_os()).default.tmpdir(), `yarn-${prefix || ''}-${Date.now()}-${Math.random()}`); - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dir); - yield mkdirp(dir); - return dir; - }); - - return function makeTempDir(_x33) { - return _ref33.apply(this, arguments); - }; -})(); - -let readFirstAvailableStream = exports.readFirstAvailableStream = (() => { - var _ref34 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths) { - for (var _iterator15 = paths, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { - var _ref35; - - if (_isArray15) { - if (_i15 >= _iterator15.length) break; - _ref35 = _iterator15[_i15++]; - } else { - _i15 = _iterator15.next(); - if (_i15.done) break; - _ref35 = _i15.value; - } - - const path = _ref35; - - try { - const fd = yield open(path, 'r'); - return (_fs || _load_fs()).default.createReadStream(path, { fd }); - } catch (err) { - // Try the next one - } - } - return null; - }); - - return function readFirstAvailableStream(_x34) { - return _ref34.apply(this, arguments); - }; -})(); - -let getFirstSuitableFolder = exports.getFirstSuitableFolder = (() => { - var _ref36 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths, mode = constants.W_OK | constants.X_OK) { - const result = { - skipped: [], - folder: null - }; - - for (var _iterator16 = paths, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) { - var _ref37; - - if (_isArray16) { - if (_i16 >= _iterator16.length) break; - _ref37 = _iterator16[_i16++]; - } else { - _i16 = _iterator16.next(); - if (_i16.done) break; - _ref37 = _i16.value; - } - - const folder = _ref37; - - try { - yield mkdirp(folder); - yield access(folder, mode); - - result.folder = folder; - - return result; - } catch (error) { - result.skipped.push({ - error, - folder - }); - } - } - return result; - }); - - return function getFirstSuitableFolder(_x35) { - return _ref36.apply(this, arguments); - }; -})(); - -exports.copy = copy; -exports.readFile = readFile; -exports.readFileRaw = readFileRaw; -exports.normalizeOS = normalizeOS; - -var _fs; - -function _load_fs() { - return _fs = _interopRequireDefault(__webpack_require__(5)); -} - -var _glob; - -function _load_glob() { - return _glob = _interopRequireDefault(__webpack_require__(99)); -} - -var _os; - -function _load_os() { - return _os = _interopRequireDefault(__webpack_require__(46)); -} - -var _path; - -function _load_path() { - return _path = _interopRequireDefault(__webpack_require__(0)); -} - -var _blockingQueue; - -function _load_blockingQueue() { - return _blockingQueue = _interopRequireDefault(__webpack_require__(110)); -} - -var _promise; - -function _load_promise() { - return _promise = _interopRequireWildcard(__webpack_require__(50)); -} - -var _promise2; - -function _load_promise2() { - return _promise2 = __webpack_require__(50); -} - -var _map; - -function _load_map() { - return _map = _interopRequireDefault(__webpack_require__(29)); -} - -var _fsNormalized; - -function _load_fsNormalized() { - return _fsNormalized = __webpack_require__(218); -} - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const constants = exports.constants = typeof (_fs || _load_fs()).default.constants !== 'undefined' ? (_fs || _load_fs()).default.constants : { - R_OK: (_fs || _load_fs()).default.R_OK, - W_OK: (_fs || _load_fs()).default.W_OK, - X_OK: (_fs || _load_fs()).default.X_OK -}; - -const lockQueue = exports.lockQueue = new (_blockingQueue || _load_blockingQueue()).default('fs lock'); - -const readFileBuffer = exports.readFileBuffer = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readFile); -const open = exports.open = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.open); -const writeFile = exports.writeFile = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.writeFile); -const readlink = exports.readlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readlink); -const realpath = exports.realpath = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.realpath); -const readdir = exports.readdir = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readdir); -const rename = exports.rename = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.rename); -const access = exports.access = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.access); -const stat = exports.stat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.stat); -const mkdirp = exports.mkdirp = (0, (_promise2 || _load_promise2()).promisify)(__webpack_require__(145)); -const exists = exports.exists = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.exists, true); -const lstat = exports.lstat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.lstat); -const chmod = exports.chmod = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.chmod); -const link = exports.link = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.link); -const glob = exports.glob = (0, (_promise2 || _load_promise2()).promisify)((_glob || _load_glob()).default); -exports.unlink = (_fsNormalized || _load_fsNormalized()).unlink; - -// fs.copyFile uses the native file copying instructions on the system, performing much better -// than any JS-based solution and consumes fewer resources. Repeated testing to fine tune the -// concurrency level revealed 128 as the sweet spot on a quad-core, 16 CPU Intel system with SSD. - -const CONCURRENT_QUEUE_ITEMS = (_fs || _load_fs()).default.copyFile ? 128 : 4; - -const fsSymlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.symlink); -const invariant = __webpack_require__(9); -const stripBOM = __webpack_require__(160); - -const noop = () => {}; - -function copy(src, dest, reporter) { - return copyBulk([{ src, dest }], reporter); -} - -function _readFile(loc, encoding) { - return new Promise((resolve, reject) => { - (_fs || _load_fs()).default.readFile(loc, encoding, function (err, content) { - if (err) { - reject(err); - } else { - resolve(content); - } - }); - }); -} - -function readFile(loc) { - return _readFile(loc, 'utf8').then(normalizeOS); -} - -function readFileRaw(loc) { - return _readFile(loc, 'binary'); -} - -function normalizeOS(body) { - return body.replace(/\r\n/g, '\n'); -} - -const cr = '\r'.charCodeAt(0); -const lf = '\n'.charCodeAt(0); - -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - -module.exports = require("fs"); - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -class MessageError extends Error { - constructor(msg, code) { - super(msg); - this.code = code; - } - -} - -exports.MessageError = MessageError; -class ProcessSpawnError extends MessageError { - constructor(msg, code, process) { - super(msg, code); - this.process = process; - } - -} - -exports.ProcessSpawnError = ProcessSpawnError; -class SecurityError extends MessageError {} - -exports.SecurityError = SecurityError; -class ProcessTermError extends MessageError {} - -exports.ProcessTermError = ProcessTermError; -class ResponseError extends Error { - constructor(msg, responseCode) { - super(msg); - this.responseCode = responseCode; - } - -} - -exports.ResponseError = ResponseError; -class OneTimePasswordError extends Error {} -exports.OneTimePasswordError = OneTimePasswordError; - -/***/ }), -/* 7 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscriber; }); -/* unused harmony export SafeSubscriber */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isFunction__ = __webpack_require__(154); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Observer__ = __webpack_require__(420); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__ = __webpack_require__(321); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__config__ = __webpack_require__(185); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__ = __webpack_require__(323); -/** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */ - - - - - - - -var Subscriber = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subscriber, _super); - function Subscriber(destinationOrNext, error, complete) { - var _this = _super.call(this) || this; - _this.syncErrorValue = null; - _this.syncErrorThrown = false; - _this.syncErrorThrowable = false; - _this.isStopped = false; - _this._parentSubscription = null; - switch (arguments.length) { - case 0: - _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; - break; - case 1: - if (!destinationOrNext) { - _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; - break; - } - if (typeof destinationOrNext === 'object') { - if (destinationOrNext instanceof Subscriber) { - _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable; - _this.destination = destinationOrNext; - destinationOrNext.add(_this); - } - else { - _this.syncErrorThrowable = true; - _this.destination = new SafeSubscriber(_this, destinationOrNext); - } - break; - } - default: - _this.syncErrorThrowable = true; - _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete); - break; - } - return _this; - } - Subscriber.prototype[__WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { return this; }; - Subscriber.create = function (next, error, complete) { - var subscriber = new Subscriber(next, error, complete); - subscriber.syncErrorThrowable = false; - return subscriber; - }; - Subscriber.prototype.next = function (value) { - if (!this.isStopped) { - this._next(value); - } - }; - Subscriber.prototype.error = function (err) { - if (!this.isStopped) { - this.isStopped = true; - this._error(err); - } - }; - Subscriber.prototype.complete = function () { - if (!this.isStopped) { - this.isStopped = true; - this._complete(); - } - }; - Subscriber.prototype.unsubscribe = function () { - if (this.closed) { - return; - } - this.isStopped = true; - _super.prototype.unsubscribe.call(this); - }; - Subscriber.prototype._next = function (value) { - this.destination.next(value); - }; - Subscriber.prototype._error = function (err) { - this.destination.error(err); - this.unsubscribe(); - }; - Subscriber.prototype._complete = function () { - this.destination.complete(); - this.unsubscribe(); - }; - Subscriber.prototype._unsubscribeAndRecycle = function () { - var _a = this, _parent = _a._parent, _parents = _a._parents; - this._parent = null; - this._parents = null; - this.unsubscribe(); - this.closed = false; - this.isStopped = false; - this._parent = _parent; - this._parents = _parents; - this._parentSubscription = null; - return this; - }; - return Subscriber; -}(__WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */])); - -var SafeSubscriber = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SafeSubscriber, _super); - function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) { - var _this = _super.call(this) || this; - _this._parentSubscriber = _parentSubscriber; - var next; - var context = _this; - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(observerOrNext)) { - next = observerOrNext; - } - else if (observerOrNext) { - next = observerOrNext.next; - error = observerOrNext.error; - complete = observerOrNext.complete; - if (observerOrNext !== __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]) { - context = Object.create(observerOrNext); - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(context.unsubscribe)) { - _this.add(context.unsubscribe.bind(context)); - } - context.unsubscribe = _this.unsubscribe.bind(_this); - } - } - _this._context = context; - _this._next = next; - _this._error = error; - _this._complete = complete; - return _this; - } - SafeSubscriber.prototype.next = function (value) { - if (!this.isStopped && this._next) { - var _parentSubscriber = this._parentSubscriber; - if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { - this.__tryOrUnsub(this._next, value); - } - else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) { - this.unsubscribe(); - } - } - }; - SafeSubscriber.prototype.error = function (err) { - if (!this.isStopped) { - var _parentSubscriber = this._parentSubscriber; - var useDeprecatedSynchronousErrorHandling = __WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling; - if (this._error) { - if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { - this.__tryOrUnsub(this._error, err); - this.unsubscribe(); - } - else { - this.__tryOrSetError(_parentSubscriber, this._error, err); - this.unsubscribe(); - } - } - else if (!_parentSubscriber.syncErrorThrowable) { - this.unsubscribe(); - if (useDeprecatedSynchronousErrorHandling) { - throw err; - } - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); - } - else { - if (useDeprecatedSynchronousErrorHandling) { - _parentSubscriber.syncErrorValue = err; - _parentSubscriber.syncErrorThrown = true; - } - else { - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); - } - this.unsubscribe(); - } - } - }; - SafeSubscriber.prototype.complete = function () { - var _this = this; - if (!this.isStopped) { - var _parentSubscriber = this._parentSubscriber; - if (this._complete) { - var wrappedComplete = function () { return _this._complete.call(_this._context); }; - if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { - this.__tryOrUnsub(wrappedComplete); - this.unsubscribe(); - } - else { - this.__tryOrSetError(_parentSubscriber, wrappedComplete); - this.unsubscribe(); - } - } - else { - this.unsubscribe(); - } - } - }; - SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) { - try { - fn.call(this._context, value); - } - catch (err) { - this.unsubscribe(); - if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - throw err; - } - else { - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); - } - } - }; - SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) { - if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - throw new Error('bad call'); - } - try { - fn.call(this._context, value); - } - catch (err) { - if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - parent.syncErrorValue = err; - parent.syncErrorThrown = true; - return true; - } - else { - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); - return true; - } - } - return false; - }; - SafeSubscriber.prototype._unsubscribe = function () { - var _parentSubscriber = this._parentSubscriber; - this._context = null; - this._parentSubscriber = null; - _parentSubscriber.unsubscribe(); - }; - return SafeSubscriber; -}(Subscriber)); - -//# sourceMappingURL=Subscriber.js.map - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getPathKey = getPathKey; -const os = __webpack_require__(46); -const path = __webpack_require__(0); -const userHome = __webpack_require__(67).default; - -var _require = __webpack_require__(225); - -const getCacheDir = _require.getCacheDir, - getConfigDir = _require.getConfigDir, - getDataDir = _require.getDataDir; - -const isWebpackBundle = __webpack_require__(278); - -const DEPENDENCY_TYPES = exports.DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies', 'peerDependencies']; -const OWNED_DEPENDENCY_TYPES = exports.OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies']; - -const RESOLUTIONS = exports.RESOLUTIONS = 'resolutions'; -const MANIFEST_FIELDS = exports.MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; - -const SUPPORTED_NODE_VERSIONS = exports.SUPPORTED_NODE_VERSIONS = '^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0'; - -const YARN_REGISTRY = exports.YARN_REGISTRY = 'https://registry.yarnpkg.com'; -const NPM_REGISTRY_RE = exports.NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g; - -const YARN_DOCS = exports.YARN_DOCS = 'https://yarnpkg.com/en/docs/cli/'; -const YARN_INSTALLER_SH = exports.YARN_INSTALLER_SH = 'https://yarnpkg.com/install.sh'; -const YARN_INSTALLER_MSI = exports.YARN_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi'; - -const SELF_UPDATE_VERSION_URL = exports.SELF_UPDATE_VERSION_URL = 'https://yarnpkg.com/latest-version'; - -// cache version, bump whenever we make backwards incompatible changes -const CACHE_VERSION = exports.CACHE_VERSION = 6; - -// lockfile version, bump whenever we make backwards incompatible changes -const LOCKFILE_VERSION = exports.LOCKFILE_VERSION = 1; - -// max amount of network requests to perform concurrently -const NETWORK_CONCURRENCY = exports.NETWORK_CONCURRENCY = 8; - -// HTTP timeout used when downloading packages -const NETWORK_TIMEOUT = exports.NETWORK_TIMEOUT = 30 * 1000; // in milliseconds - -// max amount of child processes to execute concurrently -const CHILD_CONCURRENCY = exports.CHILD_CONCURRENCY = 5; - -const REQUIRED_PACKAGE_KEYS = exports.REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']; - -function getPreferredCacheDirectories() { - const preferredCacheDirectories = [getCacheDir()]; - - if (process.getuid) { - // $FlowFixMe: process.getuid exists, dammit - preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache-${process.getuid()}`)); - } - - preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache`)); - - return preferredCacheDirectories; -} - -const PREFERRED_MODULE_CACHE_DIRECTORIES = exports.PREFERRED_MODULE_CACHE_DIRECTORIES = getPreferredCacheDirectories(); -const CONFIG_DIRECTORY = exports.CONFIG_DIRECTORY = getConfigDir(); -const DATA_DIRECTORY = exports.DATA_DIRECTORY = getDataDir(); -const LINK_REGISTRY_DIRECTORY = exports.LINK_REGISTRY_DIRECTORY = path.join(DATA_DIRECTORY, 'link'); -const GLOBAL_MODULE_DIRECTORY = exports.GLOBAL_MODULE_DIRECTORY = path.join(DATA_DIRECTORY, 'global'); - -const NODE_BIN_PATH = exports.NODE_BIN_PATH = process.execPath; -const YARN_BIN_PATH = exports.YARN_BIN_PATH = getYarnBinPath(); - -// Webpack needs to be configured with node.__dirname/__filename = false -function getYarnBinPath() { - if (isWebpackBundle) { - return __filename; - } else { - return path.join(__dirname, '..', 'bin', 'yarn.js'); - } -} - -const NODE_MODULES_FOLDER = exports.NODE_MODULES_FOLDER = 'node_modules'; -const NODE_PACKAGE_JSON = exports.NODE_PACKAGE_JSON = 'package.json'; - -const PNP_FILENAME = exports.PNP_FILENAME = '.pnp.js'; - -const POSIX_GLOBAL_PREFIX = exports.POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; -const FALLBACK_GLOBAL_PREFIX = exports.FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.yarn'); - -const META_FOLDER = exports.META_FOLDER = '.yarn-meta'; -const INTEGRITY_FILENAME = exports.INTEGRITY_FILENAME = '.yarn-integrity'; -const LOCKFILE_FILENAME = exports.LOCKFILE_FILENAME = 'yarn.lock'; -const METADATA_FILENAME = exports.METADATA_FILENAME = '.yarn-metadata.json'; -const TARBALL_FILENAME = exports.TARBALL_FILENAME = '.yarn-tarball.tgz'; -const CLEAN_FILENAME = exports.CLEAN_FILENAME = '.yarnclean'; - -const NPM_LOCK_FILENAME = exports.NPM_LOCK_FILENAME = 'package-lock.json'; -const NPM_SHRINKWRAP_FILENAME = exports.NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'; - -const DEFAULT_INDENT = exports.DEFAULT_INDENT = ' '; -const SINGLE_INSTANCE_PORT = exports.SINGLE_INSTANCE_PORT = 31997; -const SINGLE_INSTANCE_FILENAME = exports.SINGLE_INSTANCE_FILENAME = '.yarn-single-instance'; - -const ENV_PATH_KEY = exports.ENV_PATH_KEY = getPathKey(process.platform, process.env); - -function getPathKey(platform, env) { - let pathKey = 'PATH'; - - // windows calls its path "Path" usually, but this is not guaranteed. - if (platform === 'win32') { - pathKey = 'Path'; - - for (const key in env) { - if (key.toLowerCase() === 'path') { - pathKey = key; - } - } - } - - return pathKey; -} - -const VERSION_COLOR_SCHEME = exports.VERSION_COLOR_SCHEME = { - major: 'red', - premajor: 'red', - minor: 'yellow', - preminor: 'yellow', - patch: 'green', - prepatch: 'green', - prerelease: 'red', - unchanged: 'white', - unknown: 'red' -}; - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - - - -/** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. - */ - -var NODE_ENV = process.env.NODE_ENV; - -var invariant = function(condition, format, a, b, c, d, e, f) { - if (NODE_ENV !== 'production') { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - } - - if (!condition) { - var error; - if (format === undefined) { - error = new Error( - 'Minified exception occurred; use the non-minified dev environment ' + - 'for the full error message and additional helpful warnings.' - ); - } else { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - error = new Error( - format.replace(/%s/g, function() { return args[argIndex++]; }) - ); - error.name = 'Invariant Violation'; - } - - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; - } -}; - -module.exports = invariant; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var YAMLException = __webpack_require__(54); - -var TYPE_CONSTRUCTOR_OPTIONS = [ - 'kind', - 'resolve', - 'construct', - 'instanceOf', - 'predicate', - 'represent', - 'defaultStyle', - 'styleAliases' -]; - -var YAML_NODE_KINDS = [ - 'scalar', - 'sequence', - 'mapping' -]; - -function compileStyleAliases(map) { - var result = {}; - - if (map !== null) { - Object.keys(map).forEach(function (style) { - map[style].forEach(function (alias) { - result[String(alias)] = style; - }); - }); - } - - return result; -} - -function Type(tag, options) { - options = options || {}; - - Object.keys(options).forEach(function (name) { - if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { - throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); - } - }); - - // TODO: Add tag format check. - this.tag = tag; - this.kind = options['kind'] || null; - this.resolve = options['resolve'] || function () { return true; }; - this.construct = options['construct'] || function (data) { return data; }; - this.instanceOf = options['instanceOf'] || null; - this.predicate = options['predicate'] || null; - this.represent = options['represent'] || null; - this.defaultStyle = options['defaultStyle'] || null; - this.styleAliases = compileStyleAliases(options['styleAliases'] || null); - - if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { - throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); - } -} - -module.exports = Type; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports) { - -module.exports = require("crypto"); - -/***/ }), -/* 12 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Observable; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_canReportError__ = __webpack_require__(322); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__ = __webpack_require__(932); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__ = __webpack_require__(117); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_pipe__ = __webpack_require__(324); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__config__ = __webpack_require__(185); -/** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_internal_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */ - - - - - -var Observable = /*@__PURE__*/ (function () { - function Observable(subscribe) { - this._isScalar = false; - if (subscribe) { - this._subscribe = subscribe; - } - } - Observable.prototype.lift = function (operator) { - var observable = new Observable(); - observable.source = this; - observable.operator = operator; - return observable; - }; - Observable.prototype.subscribe = function (observerOrNext, error, complete) { - var operator = this.operator; - var sink = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__["a" /* toSubscriber */])(observerOrNext, error, complete); - if (operator) { - operator.call(sink, this.source); - } - else { - sink.add(this.source || (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ? - this._subscribe(sink) : - this._trySubscribe(sink)); - } - if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - if (sink.syncErrorThrowable) { - sink.syncErrorThrowable = false; - if (sink.syncErrorThrown) { - throw sink.syncErrorValue; - } - } - } - return sink; - }; - Observable.prototype._trySubscribe = function (sink) { - try { - return this._subscribe(sink); - } - catch (err) { - if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - sink.syncErrorThrown = true; - sink.syncErrorValue = err; - } - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_canReportError__["a" /* canReportError */])(sink)) { - sink.error(err); - } - else { - console.warn(err); - } - } - }; - Observable.prototype.forEach = function (next, promiseCtor) { - var _this = this; - promiseCtor = getPromiseCtor(promiseCtor); - return new promiseCtor(function (resolve, reject) { - var subscription; - subscription = _this.subscribe(function (value) { - try { - next(value); - } - catch (err) { - reject(err); - if (subscription) { - subscription.unsubscribe(); - } - } - }, reject, resolve); - }); - }; - Observable.prototype._subscribe = function (subscriber) { - var source = this.source; - return source && source.subscribe(subscriber); - }; - Observable.prototype[__WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__["a" /* observable */]] = function () { - return this; - }; - Observable.prototype.pipe = function () { - var operations = []; - for (var _i = 0; _i < arguments.length; _i++) { - operations[_i] = arguments[_i]; - } - if (operations.length === 0) { - return this; - } - return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_pipe__["b" /* pipeFromArray */])(operations)(this); - }; - Observable.prototype.toPromise = function (promiseCtor) { - var _this = this; - promiseCtor = getPromiseCtor(promiseCtor); - return new promiseCtor(function (resolve, reject) { - var value; - _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); }); - }); - }; - Observable.create = function (subscribe) { - return new Observable(subscribe); - }; - return Observable; -}()); - -function getPromiseCtor(promiseCtor) { - if (!promiseCtor) { - promiseCtor = __WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].Promise || Promise; - } - if (!promiseCtor) { - throw new Error('no Promise impl found'); - } - return promiseCtor; -} -//# sourceMappingURL=Observable.js.map - - -/***/ }), -/* 13 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return OuterSubscriber; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(7); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ - - -var OuterSubscriber = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](OuterSubscriber, _super); - function OuterSubscriber() { - return _super !== null && _super.apply(this, arguments) || this; - } - OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.destination.next(innerValue); - }; - OuterSubscriber.prototype.notifyError = function (error, innerSub) { - this.destination.error(error); - }; - OuterSubscriber.prototype.notifyComplete = function (innerSub) { - this.destination.complete(); - }; - return OuterSubscriber; -}(__WEBPACK_IMPORTED_MODULE_1__Subscriber__["a" /* Subscriber */])); - -//# sourceMappingURL=OuterSubscriber.js.map - - -/***/ }), -/* 14 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = subscribeToResult; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__ = __webpack_require__(84); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__subscribeTo__ = __webpack_require__(446); -/** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo PURE_IMPORTS_END */ - - -function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, destination) { - if (destination === void 0) { - destination = new __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__["a" /* InnerSubscriber */](outerSubscriber, outerValue, outerIndex); - } - if (destination.closed) { - return; - } - return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__subscribeTo__["a" /* subscribeTo */])(result)(destination); -} -//# sourceMappingURL=subscribeToResult.js.map - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* eslint-disable node/no-deprecated-api */ - - - -var buffer = __webpack_require__(64) -var Buffer = buffer.Buffer - -var safer = {} - -var key - -for (key in buffer) { - if (!buffer.hasOwnProperty(key)) continue - if (key === 'SlowBuffer' || key === 'Buffer') continue - safer[key] = buffer[key] -} - -var Safer = safer.Buffer = {} -for (key in Buffer) { - if (!Buffer.hasOwnProperty(key)) continue - if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue - Safer[key] = Buffer[key] -} - -safer.Buffer.prototype = Buffer.prototype - -if (!Safer.from || Safer.from === Uint8Array.from) { - Safer.from = function (value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value) - } - if (value && typeof value.length === 'undefined') { - throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value) - } - return Buffer(value, encodingOrOffset, length) - } -} - -if (!Safer.alloc) { - Safer.alloc = function (size, fill, encoding) { - if (typeof size !== 'number') { - throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) - } - if (size < 0 || size >= 2 * (1 << 30)) { - throw new RangeError('The value "' + size + '" is invalid for option "size"') - } - var buf = Buffer(size) - if (!fill || fill.length === 0) { - buf.fill(0) - } else if (typeof encoding === 'string') { - buf.fill(fill, encoding) - } else { - buf.fill(fill) - } - return buf - } -} - -if (!safer.kStringMaxLength) { - try { - safer.kStringMaxLength = process.binding('buffer').kStringMaxLength - } catch (e) { - // we can't determine kStringMaxLength in environments where process.binding - // is unsupported, so let's not set it - } -} - -if (!safer.constants) { - safer.constants = { - MAX_LENGTH: safer.kMaxLength - } - if (safer.kStringMaxLength) { - safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength - } -} - -module.exports = safer - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright (c) 2012, Mark Cavage. All rights reserved. -// Copyright 2015 Joyent, Inc. - -var assert = __webpack_require__(28); -var Stream = __webpack_require__(23).Stream; -var util = __webpack_require__(3); - - -///--- Globals - -/* JSSTYLED */ -var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/; - - -///--- Internal - -function _capitalize(str) { - return (str.charAt(0).toUpperCase() + str.slice(1)); -} - -function _toss(name, expected, oper, arg, actual) { - throw new assert.AssertionError({ - message: util.format('%s (%s) is required', name, expected), - actual: (actual === undefined) ? typeof (arg) : actual(arg), - expected: expected, - operator: oper || '===', - stackStartFunction: _toss.caller - }); -} - -function _getClass(arg) { - return (Object.prototype.toString.call(arg).slice(8, -1)); -} - -function noop() { - // Why even bother with asserts? -} - - -///--- Exports - -var types = { - bool: { - check: function (arg) { return typeof (arg) === 'boolean'; } - }, - func: { - check: function (arg) { return typeof (arg) === 'function'; } - }, - string: { - check: function (arg) { return typeof (arg) === 'string'; } - }, - object: { - check: function (arg) { - return typeof (arg) === 'object' && arg !== null; - } - }, - number: { - check: function (arg) { - return typeof (arg) === 'number' && !isNaN(arg); - } - }, - finite: { - check: function (arg) { - return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg); - } - }, - buffer: { - check: function (arg) { return Buffer.isBuffer(arg); }, - operator: 'Buffer.isBuffer' - }, - array: { - check: function (arg) { return Array.isArray(arg); }, - operator: 'Array.isArray' - }, - stream: { - check: function (arg) { return arg instanceof Stream; }, - operator: 'instanceof', - actual: _getClass - }, - date: { - check: function (arg) { return arg instanceof Date; }, - operator: 'instanceof', - actual: _getClass - }, - regexp: { - check: function (arg) { return arg instanceof RegExp; }, - operator: 'instanceof', - actual: _getClass - }, - uuid: { - check: function (arg) { - return typeof (arg) === 'string' && UUID_REGEXP.test(arg); - }, - operator: 'isUUID' - } -}; - -function _setExports(ndebug) { - var keys = Object.keys(types); - var out; - - /* re-export standard assert */ - if (process.env.NODE_NDEBUG) { - out = noop; - } else { - out = function (arg, msg) { - if (!arg) { - _toss(msg, 'true', arg); - } - }; - } - - /* standard checks */ - keys.forEach(function (k) { - if (ndebug) { - out[k] = noop; - return; - } - var type = types[k]; - out[k] = function (arg, msg) { - if (!type.check(arg)) { - _toss(msg, k, type.operator, arg, type.actual); - } - }; - }); - - /* optional checks */ - keys.forEach(function (k) { - var name = 'optional' + _capitalize(k); - if (ndebug) { - out[name] = noop; - return; - } - var type = types[k]; - out[name] = function (arg, msg) { - if (arg === undefined || arg === null) { - return; - } - if (!type.check(arg)) { - _toss(msg, k, type.operator, arg, type.actual); - } - }; - }); - - /* arrayOf checks */ - keys.forEach(function (k) { - var name = 'arrayOf' + _capitalize(k); - if (ndebug) { - out[name] = noop; - return; - } - var type = types[k]; - var expected = '[' + k + ']'; - out[name] = function (arg, msg) { - if (!Array.isArray(arg)) { - _toss(msg, expected, type.operator, arg, type.actual); - } - var i; - for (i = 0; i < arg.length; i++) { - if (!type.check(arg[i])) { - _toss(msg, expected, type.operator, arg, type.actual); - } - } - }; - }); - - /* optionalArrayOf checks */ - keys.forEach(function (k) { - var name = 'optionalArrayOf' + _capitalize(k); - if (ndebug) { - out[name] = noop; - return; - } - var type = types[k]; - var expected = '[' + k + ']'; - out[name] = function (arg, msg) { - if (arg === undefined || arg === null) { - return; - } - if (!Array.isArray(arg)) { - _toss(msg, expected, type.operator, arg, type.actual); - } - var i; - for (i = 0; i < arg.length; i++) { - if (!type.check(arg[i])) { - _toss(msg, expected, type.operator, arg, type.actual); - } - } - }; - }); - - /* re-export built-in assertions */ - Object.keys(assert).forEach(function (k) { - if (k === 'AssertionError') { - out[k] = assert[k]; - return; - } - if (ndebug) { - out[k] = noop; - return; - } - out[k] = assert[k]; - }); - - /* export ourselves (for unit tests _only_) */ - out._setExports = _setExports; - - return out; -} - -module.exports = _setExports(process.env.NODE_NDEBUG); - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 -var global = module.exports = typeof window != 'undefined' && window.Math == Math - ? window : typeof self != 'undefined' && self.Math == Math ? self - // eslint-disable-next-line no-new-func - : Function('return this')(); -if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.sortAlpha = sortAlpha; -exports.sortOptionsByFlags = sortOptionsByFlags; -exports.entries = entries; -exports.removePrefix = removePrefix; -exports.removeSuffix = removeSuffix; -exports.addSuffix = addSuffix; -exports.hyphenate = hyphenate; -exports.camelCase = camelCase; -exports.compareSortedArrays = compareSortedArrays; -exports.sleep = sleep; -const _camelCase = __webpack_require__(230); - -function sortAlpha(a, b) { - // sort alphabetically in a deterministic way - const shortLen = Math.min(a.length, b.length); - for (let i = 0; i < shortLen; i++) { - const aChar = a.charCodeAt(i); - const bChar = b.charCodeAt(i); - if (aChar !== bChar) { - return aChar - bChar; - } - } - return a.length - b.length; -} - -function sortOptionsByFlags(a, b) { - const aOpt = a.flags.replace(/-/g, ''); - const bOpt = b.flags.replace(/-/g, ''); - return sortAlpha(aOpt, bOpt); -} - -function entries(obj) { - const entries = []; - if (obj) { - for (const key in obj) { - entries.push([key, obj[key]]); - } - } - return entries; -} - -function removePrefix(pattern, prefix) { - if (pattern.startsWith(prefix)) { - pattern = pattern.slice(prefix.length); - } - - return pattern; -} - -function removeSuffix(pattern, suffix) { - if (pattern.endsWith(suffix)) { - return pattern.slice(0, -suffix.length); - } - - return pattern; -} - -function addSuffix(pattern, suffix) { - if (!pattern.endsWith(suffix)) { - return pattern + suffix; - } - - return pattern; -} - -function hyphenate(str) { - return str.replace(/[A-Z]/g, match => { - return '-' + match.charAt(0).toLowerCase(); - }); -} - -function camelCase(str) { - if (/[A-Z]/.test(str)) { - return null; - } else { - return _camelCase(str); - } -} - -function compareSortedArrays(array1, array2) { - if (array1.length !== array2.length) { - return false; - } - for (let i = 0, len = array1.length; i < len; i++) { - if (array1[i] !== array2[i]) { - return false; - } - } - return true; -} - -function sleep(ms) { - return new Promise(resolve => { - setTimeout(resolve, ms); - }); -} - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.stringify = exports.parse = undefined; - -var _asyncToGenerator2; - -function _load_asyncToGenerator() { - return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); -} - -var _parse; - -function _load_parse() { - return _parse = __webpack_require__(105); -} - -Object.defineProperty(exports, 'parse', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_parse || _load_parse()).default; - } -}); - -var _stringify; - -function _load_stringify() { - return _stringify = __webpack_require__(199); -} - -Object.defineProperty(exports, 'stringify', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_stringify || _load_stringify()).default; - } -}); -exports.implodeEntry = implodeEntry; -exports.explodeEntry = explodeEntry; - -var _misc; - -function _load_misc() { - return _misc = __webpack_require__(18); -} - -var _normalizePattern; - -function _load_normalizePattern() { - return _normalizePattern = __webpack_require__(37); -} - -var _parse2; - -function _load_parse2() { - return _parse2 = _interopRequireDefault(__webpack_require__(105)); -} - -var _constants; - -function _load_constants() { - return _constants = __webpack_require__(8); -} - -var _fs; - -function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); -} - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const invariant = __webpack_require__(9); - -const path = __webpack_require__(0); -const ssri = __webpack_require__(65); - -function getName(pattern) { - return (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern).name; -} - -function blankObjectUndefined(obj) { - return obj && Object.keys(obj).length ? obj : undefined; -} - -function keyForRemote(remote) { - return remote.resolved || (remote.reference && remote.hash ? `${remote.reference}#${remote.hash}` : null); -} - -function serializeIntegrity(integrity) { - // We need this because `Integrity.toString()` does not use sorting to ensure a stable string output - // See https://git.io/vx2Hy - return integrity.toString().split(' ').sort().join(' '); -} - -function implodeEntry(pattern, obj) { - const inferredName = getName(pattern); - const integrity = obj.integrity ? serializeIntegrity(obj.integrity) : ''; - const imploded = { - name: inferredName === obj.name ? undefined : obj.name, - version: obj.version, - uid: obj.uid === obj.version ? undefined : obj.uid, - resolved: obj.resolved, - registry: obj.registry === 'npm' ? undefined : obj.registry, - dependencies: blankObjectUndefined(obj.dependencies), - optionalDependencies: blankObjectUndefined(obj.optionalDependencies), - permissions: blankObjectUndefined(obj.permissions), - prebuilt2Variants: blankObjectUndefined(obj.prebuilt2Variants) - }; - if (integrity) { - imploded.integrity = integrity; - } - return imploded; -} - -function explodeEntry(pattern, obj) { - obj.optionalDependencies = obj.optionalDependencies || {}; - obj.dependencies = obj.dependencies || {}; - obj.uid = obj.uid || obj.version; - obj.permissions = obj.permissions || {}; - obj.registry = obj.registry || 'npm'; - obj.name = obj.name || getName(pattern); - const integrity = obj.integrity; - if (integrity && integrity.isIntegrity) { - obj.integrity = ssri.parse(integrity); - } - return obj; -} - -class Lockfile { - constructor({ cache, source, parseResultType } = {}) { - this.source = source || ''; - this.cache = cache; - this.parseResultType = parseResultType; - } - - // source string if the `cache` was parsed - - - // if true, we're parsing an old yarn file and need to update integrity fields - hasEntriesExistWithoutIntegrity() { - if (!this.cache) { - return false; - } - - for (const key in this.cache) { - // $FlowFixMe - `this.cache` is clearly defined at this point - if (!/^.*@(file:|http)/.test(key) && this.cache[key] && !this.cache[key].integrity) { - return true; - } - } - - return false; - } - - static fromDirectory(dir, reporter) { - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - // read the manifest in this directory - const lockfileLoc = path.join(dir, (_constants || _load_constants()).LOCKFILE_FILENAME); - - let lockfile; - let rawLockfile = ''; - let parseResult; - - if (yield (_fs || _load_fs()).exists(lockfileLoc)) { - rawLockfile = yield (_fs || _load_fs()).readFile(lockfileLoc); - parseResult = (0, (_parse2 || _load_parse2()).default)(rawLockfile, lockfileLoc); - - if (reporter) { - if (parseResult.type === 'merge') { - reporter.info(reporter.lang('lockfileMerged')); - } else if (parseResult.type === 'conflict') { - reporter.warn(reporter.lang('lockfileConflict')); - } - } - - lockfile = parseResult.object; - } else if (reporter) { - reporter.info(reporter.lang('noLockfileFound')); - } - - if (lockfile && lockfile.__metadata) { - const lockfilev2 = lockfile; - lockfile = {}; - } - - return new Lockfile({ cache: lockfile, source: rawLockfile, parseResultType: parseResult && parseResult.type }); - })(); - } - - getLocked(pattern) { - const cache = this.cache; - if (!cache) { - return undefined; - } - - const shrunk = pattern in cache && cache[pattern]; - - if (typeof shrunk === 'string') { - return this.getLocked(shrunk); - } else if (shrunk) { - explodeEntry(pattern, shrunk); - return shrunk; - } - - return undefined; - } - - removePattern(pattern) { - const cache = this.cache; - if (!cache) { - return; - } - delete cache[pattern]; - } - - getLockfile(patterns) { - const lockfile = {}; - const seen = new Map(); - - // order by name so that lockfile manifest is assigned to the first dependency with this manifest - // the others that have the same remoteKey will just refer to the first - // ordering allows for consistency in lockfile when it is serialized - const sortedPatternsKeys = Object.keys(patterns).sort((_misc || _load_misc()).sortAlpha); - - for (var _iterator = sortedPatternsKeys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref; - - if (_isArray) { - if (_i >= _iterator.length) break; - _ref = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref = _i.value; - } - - const pattern = _ref; - - const pkg = patterns[pattern]; - const remote = pkg._remote, - ref = pkg._reference; - - invariant(ref, 'Package is missing a reference'); - invariant(remote, 'Package is missing a remote'); - - const remoteKey = keyForRemote(remote); - const seenPattern = remoteKey && seen.get(remoteKey); - if (seenPattern) { - // no point in duplicating it - lockfile[pattern] = seenPattern; - - // if we're relying on our name being inferred and two of the patterns have - // different inferred names then we need to set it - if (!seenPattern.name && getName(pattern) !== pkg.name) { - seenPattern.name = pkg.name; - } - continue; - } - const obj = implodeEntry(pattern, { - name: pkg.name, - version: pkg.version, - uid: pkg._uid, - resolved: remote.resolved, - integrity: remote.integrity, - registry: remote.registry, - dependencies: pkg.dependencies, - peerDependencies: pkg.peerDependencies, - optionalDependencies: pkg.optionalDependencies, - permissions: ref.permissions, - prebuilt2Variants: pkg.prebuilt2Variants - }); - - lockfile[pattern] = obj; - - if (remoteKey) { - seen.set(remoteKey, obj); - } - } - - return lockfile; - } -} -exports.default = Lockfile; - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -var store = __webpack_require__(133)('wks'); -var uid = __webpack_require__(137); -var Symbol = __webpack_require__(17).Symbol; -var USE_SYMBOL = typeof Symbol == 'function'; - -var $exports = module.exports = function (name) { - return store[name] || (store[name] = - USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); -}; - -$exports.store = store; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.__esModule = true; - -var _assign = __webpack_require__(591); - -var _assign2 = _interopRequireDefault(_assign); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = _assign2.default || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; -}; - -/***/ }), -/* 22 */ -/***/ (function(module, exports) { - -exports = module.exports = SemVer; - -// The debug function is excluded entirely from the minified version. -/* nomin */ var debug; -/* nomin */ if (typeof process === 'object' && - /* nomin */ process.env && - /* nomin */ process.env.NODE_DEBUG && - /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG)) - /* nomin */ debug = function() { - /* nomin */ var args = Array.prototype.slice.call(arguments, 0); - /* nomin */ args.unshift('SEMVER'); - /* nomin */ console.log.apply(console, args); - /* nomin */ }; -/* nomin */ else - /* nomin */ debug = function() {}; - -// Note: this is the semver.org version of the spec that it implements -// Not necessarily the package version of this code. -exports.SEMVER_SPEC_VERSION = '2.0.0'; - -var MAX_LENGTH = 256; -var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; - -// Max safe segment length for coercion. -var MAX_SAFE_COMPONENT_LENGTH = 16; - -// The actual regexps go on exports.re -var re = exports.re = []; -var src = exports.src = []; -var R = 0; - -// The following Regular Expressions can be used for tokenizing, -// validating, and parsing SemVer version strings. - -// ## Numeric Identifier -// A single `0`, or a non-zero digit followed by zero or more digits. - -var NUMERICIDENTIFIER = R++; -src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'; -var NUMERICIDENTIFIERLOOSE = R++; -src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'; - - -// ## Non-numeric Identifier -// Zero or more digits, followed by a letter or hyphen, and then zero or -// more letters, digits, or hyphens. - -var NONNUMERICIDENTIFIER = R++; -src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'; - - -// ## Main Version -// Three dot-separated numeric identifiers. - -var MAINVERSION = R++; -src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')'; - -var MAINVERSIONLOOSE = R++; -src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')'; - -// ## Pre-release Version Identifier -// A numeric identifier, or a non-numeric identifier. - -var PRERELEASEIDENTIFIER = R++; -src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + - '|' + src[NONNUMERICIDENTIFIER] + ')'; - -var PRERELEASEIDENTIFIERLOOSE = R++; -src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + - '|' + src[NONNUMERICIDENTIFIER] + ')'; - - -// ## Pre-release Version -// Hyphen, followed by one or more dot-separated pre-release version -// identifiers. - -var PRERELEASE = R++; -src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + - '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'; - -var PRERELEASELOOSE = R++; -src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + - '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'; - -// ## Build Metadata Identifier -// Any combination of digits, letters, or hyphens. - -var BUILDIDENTIFIER = R++; -src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'; - -// ## Build Metadata -// Plus sign, followed by one or more period-separated build metadata -// identifiers. - -var BUILD = R++; -src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + - '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'; - - -// ## Full Version String -// A main version, followed optionally by a pre-release version and -// build metadata. - -// Note that the only major, minor, patch, and pre-release sections of -// the version string are capturing groups. The build metadata is not a -// capturing group, because it should not ever be used in version -// comparison. - -var FULL = R++; -var FULLPLAIN = 'v?' + src[MAINVERSION] + - src[PRERELEASE] + '?' + - src[BUILD] + '?'; - -src[FULL] = '^' + FULLPLAIN + '$'; - -// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. -// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty -// common in the npm registry. -var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + - src[PRERELEASELOOSE] + '?' + - src[BUILD] + '?'; - -var LOOSE = R++; -src[LOOSE] = '^' + LOOSEPLAIN + '$'; - -var GTLT = R++; -src[GTLT] = '((?:<|>)?=?)'; - -// Something like "2.*" or "1.2.x". -// Note that "x.x" is a valid xRange identifer, meaning "any version" -// Only the first item is strictly required. -var XRANGEIDENTIFIERLOOSE = R++; -src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'; -var XRANGEIDENTIFIER = R++; -src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'; - -var XRANGEPLAIN = R++; -src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:' + src[PRERELEASE] + ')?' + - src[BUILD] + '?' + - ')?)?'; - -var XRANGEPLAINLOOSE = R++; -src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:' + src[PRERELEASELOOSE] + ')?' + - src[BUILD] + '?' + - ')?)?'; - -var XRANGE = R++; -src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'; -var XRANGELOOSE = R++; -src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'; - -// Coercion. -// Extract anything that could conceivably be a part of a valid semver -var COERCE = R++; -src[COERCE] = '(?:^|[^\\d])' + - '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + - '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + - '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + - '(?:$|[^\\d])'; - -// Tilde ranges. -// Meaning is "reasonably at or greater than" -var LONETILDE = R++; -src[LONETILDE] = '(?:~>?)'; - -var TILDETRIM = R++; -src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'; -re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g'); -var tildeTrimReplace = '$1~'; - -var TILDE = R++; -src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'; -var TILDELOOSE = R++; -src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'; - -// Caret ranges. -// Meaning is "at least and backwards compatible with" -var LONECARET = R++; -src[LONECARET] = '(?:\\^)'; - -var CARETTRIM = R++; -src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'; -re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g'); -var caretTrimReplace = '$1^'; - -var CARET = R++; -src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'; -var CARETLOOSE = R++; -src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'; - -// A simple gt/lt/eq thing, or just "" to indicate "any version" -var COMPARATORLOOSE = R++; -src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'; -var COMPARATOR = R++; -src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'; - - -// An expression to strip any whitespace between the gtlt and the thing -// it modifies, so that `> 1.2.3` ==> `>1.2.3` -var COMPARATORTRIM = R++; -src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + - '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'; - -// this one has to use the /g flag -re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g'); -var comparatorTrimReplace = '$1$2$3'; - - -// Something like `1.2.3 - 1.2.4` -// Note that these all use the loose form, because they'll be -// checked against either the strict or loose comparator form -// later. -var HYPHENRANGE = R++; -src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAIN] + ')' + - '\\s*$'; - -var HYPHENRANGELOOSE = R++; -src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s*$'; - -// Star ranges basically just allow anything at all. -var STAR = R++; -src[STAR] = '(<|>)?=?\\s*\\*'; - -// Compile to actual regexp objects. -// All are flag-free, unless they were created above with a flag. -for (var i = 0; i < R; i++) { - debug(i, src[i]); - if (!re[i]) - re[i] = new RegExp(src[i]); -} - -exports.parse = parse; -function parse(version, loose) { - if (version instanceof SemVer) - return version; - - if (typeof version !== 'string') - return null; - - if (version.length > MAX_LENGTH) - return null; - - var r = loose ? re[LOOSE] : re[FULL]; - if (!r.test(version)) - return null; - - try { - return new SemVer(version, loose); - } catch (er) { - return null; - } -} - -exports.valid = valid; -function valid(version, loose) { - var v = parse(version, loose); - return v ? v.version : null; -} - - -exports.clean = clean; -function clean(version, loose) { - var s = parse(version.trim().replace(/^[=v]+/, ''), loose); - return s ? s.version : null; -} - -exports.SemVer = SemVer; - -function SemVer(version, loose) { - if (version instanceof SemVer) { - if (version.loose === loose) - return version; - else - version = version.version; - } else if (typeof version !== 'string') { - throw new TypeError('Invalid Version: ' + version); - } - - if (version.length > MAX_LENGTH) - throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') - - if (!(this instanceof SemVer)) - return new SemVer(version, loose); - - debug('SemVer', version, loose); - this.loose = loose; - var m = version.trim().match(loose ? re[LOOSE] : re[FULL]); - - if (!m) - throw new TypeError('Invalid Version: ' + version); - - this.raw = version; - - // these are actually numbers - this.major = +m[1]; - this.minor = +m[2]; - this.patch = +m[3]; - - if (this.major > MAX_SAFE_INTEGER || this.major < 0) - throw new TypeError('Invalid major version') - - if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) - throw new TypeError('Invalid minor version') - - if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) - throw new TypeError('Invalid patch version') - - // numberify any prerelease numeric ids - if (!m[4]) - this.prerelease = []; - else - this.prerelease = m[4].split('.').map(function(id) { - if (/^[0-9]+$/.test(id)) { - var num = +id; - if (num >= 0 && num < MAX_SAFE_INTEGER) - return num; - } - return id; - }); - - this.build = m[5] ? m[5].split('.') : []; - this.format(); -} - -SemVer.prototype.format = function() { - this.version = this.major + '.' + this.minor + '.' + this.patch; - if (this.prerelease.length) - this.version += '-' + this.prerelease.join('.'); - return this.version; -}; - -SemVer.prototype.toString = function() { - return this.version; -}; - -SemVer.prototype.compare = function(other) { - debug('SemVer.compare', this.version, this.loose, other); - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - return this.compareMain(other) || this.comparePre(other); -}; - -SemVer.prototype.compareMain = function(other) { - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - return compareIdentifiers(this.major, other.major) || - compareIdentifiers(this.minor, other.minor) || - compareIdentifiers(this.patch, other.patch); -}; - -SemVer.prototype.comparePre = function(other) { - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - // NOT having a prerelease is > having one - if (this.prerelease.length && !other.prerelease.length) - return -1; - else if (!this.prerelease.length && other.prerelease.length) - return 1; - else if (!this.prerelease.length && !other.prerelease.length) - return 0; - - var i = 0; - do { - var a = this.prerelease[i]; - var b = other.prerelease[i]; - debug('prerelease compare', i, a, b); - if (a === undefined && b === undefined) - return 0; - else if (b === undefined) - return 1; - else if (a === undefined) - return -1; - else if (a === b) - continue; - else - return compareIdentifiers(a, b); - } while (++i); -}; - -// preminor will bump the version up to the next minor release, and immediately -// down to pre-release. premajor and prepatch work the same way. -SemVer.prototype.inc = function(release, identifier) { - switch (release) { - case 'premajor': - this.prerelease.length = 0; - this.patch = 0; - this.minor = 0; - this.major++; - this.inc('pre', identifier); - break; - case 'preminor': - this.prerelease.length = 0; - this.patch = 0; - this.minor++; - this.inc('pre', identifier); - break; - case 'prepatch': - // If this is already a prerelease, it will bump to the next version - // drop any prereleases that might already exist, since they are not - // relevant at this point. - this.prerelease.length = 0; - this.inc('patch', identifier); - this.inc('pre', identifier); - break; - // If the input is a non-prerelease version, this acts the same as - // prepatch. - case 'prerelease': - if (this.prerelease.length === 0) - this.inc('patch', identifier); - this.inc('pre', identifier); - break; - - case 'major': - // If this is a pre-major version, bump up to the same major version. - // Otherwise increment major. - // 1.0.0-5 bumps to 1.0.0 - // 1.1.0 bumps to 2.0.0 - if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) - this.major++; - this.minor = 0; - this.patch = 0; - this.prerelease = []; - break; - case 'minor': - // If this is a pre-minor version, bump up to the same minor version. - // Otherwise increment minor. - // 1.2.0-5 bumps to 1.2.0 - // 1.2.1 bumps to 1.3.0 - if (this.patch !== 0 || this.prerelease.length === 0) - this.minor++; - this.patch = 0; - this.prerelease = []; - break; - case 'patch': - // If this is not a pre-release version, it will increment the patch. - // If it is a pre-release it will bump up to the same patch version. - // 1.2.0-5 patches to 1.2.0 - // 1.2.0 patches to 1.2.1 - if (this.prerelease.length === 0) - this.patch++; - this.prerelease = []; - break; - // This probably shouldn't be used publicly. - // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. - case 'pre': - if (this.prerelease.length === 0) - this.prerelease = [0]; - else { - var i = this.prerelease.length; - while (--i >= 0) { - if (typeof this.prerelease[i] === 'number') { - this.prerelease[i]++; - i = -2; - } - } - if (i === -1) // didn't increment anything - this.prerelease.push(0); - } - if (identifier) { - // 1.2.0-beta.1 bumps to 1.2.0-beta.2, - // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 - if (this.prerelease[0] === identifier) { - if (isNaN(this.prerelease[1])) - this.prerelease = [identifier, 0]; - } else - this.prerelease = [identifier, 0]; - } - break; - - default: - throw new Error('invalid increment argument: ' + release); - } - this.format(); - this.raw = this.version; - return this; -}; - -exports.inc = inc; -function inc(version, release, loose, identifier) { - if (typeof(loose) === 'string') { - identifier = loose; - loose = undefined; - } - - try { - return new SemVer(version, loose).inc(release, identifier).version; - } catch (er) { - return null; - } -} - -exports.diff = diff; -function diff(version1, version2) { - if (eq(version1, version2)) { - return null; - } else { - var v1 = parse(version1); - var v2 = parse(version2); - if (v1.prerelease.length || v2.prerelease.length) { - for (var key in v1) { - if (key === 'major' || key === 'minor' || key === 'patch') { - if (v1[key] !== v2[key]) { - return 'pre'+key; - } - } - } - return 'prerelease'; - } - for (var key in v1) { - if (key === 'major' || key === 'minor' || key === 'patch') { - if (v1[key] !== v2[key]) { - return key; - } - } - } - } -} - -exports.compareIdentifiers = compareIdentifiers; - -var numeric = /^[0-9]+$/; -function compareIdentifiers(a, b) { - var anum = numeric.test(a); - var bnum = numeric.test(b); - - if (anum && bnum) { - a = +a; - b = +b; - } - - return (anum && !bnum) ? -1 : - (bnum && !anum) ? 1 : - a < b ? -1 : - a > b ? 1 : - 0; -} - -exports.rcompareIdentifiers = rcompareIdentifiers; -function rcompareIdentifiers(a, b) { - return compareIdentifiers(b, a); -} - -exports.major = major; -function major(a, loose) { - return new SemVer(a, loose).major; -} - -exports.minor = minor; -function minor(a, loose) { - return new SemVer(a, loose).minor; -} - -exports.patch = patch; -function patch(a, loose) { - return new SemVer(a, loose).patch; -} - -exports.compare = compare; -function compare(a, b, loose) { - return new SemVer(a, loose).compare(new SemVer(b, loose)); -} - -exports.compareLoose = compareLoose; -function compareLoose(a, b) { - return compare(a, b, true); -} - -exports.rcompare = rcompare; -function rcompare(a, b, loose) { - return compare(b, a, loose); -} - -exports.sort = sort; -function sort(list, loose) { - return list.sort(function(a, b) { - return exports.compare(a, b, loose); - }); -} - -exports.rsort = rsort; -function rsort(list, loose) { - return list.sort(function(a, b) { - return exports.rcompare(a, b, loose); - }); -} - -exports.gt = gt; -function gt(a, b, loose) { - return compare(a, b, loose) > 0; -} - -exports.lt = lt; -function lt(a, b, loose) { - return compare(a, b, loose) < 0; -} - -exports.eq = eq; -function eq(a, b, loose) { - return compare(a, b, loose) === 0; -} - -exports.neq = neq; -function neq(a, b, loose) { - return compare(a, b, loose) !== 0; -} - -exports.gte = gte; -function gte(a, b, loose) { - return compare(a, b, loose) >= 0; -} - -exports.lte = lte; -function lte(a, b, loose) { - return compare(a, b, loose) <= 0; -} - -exports.cmp = cmp; -function cmp(a, op, b, loose) { - var ret; - switch (op) { - case '===': - if (typeof a === 'object') a = a.version; - if (typeof b === 'object') b = b.version; - ret = a === b; - break; - case '!==': - if (typeof a === 'object') a = a.version; - if (typeof b === 'object') b = b.version; - ret = a !== b; - break; - case '': case '=': case '==': ret = eq(a, b, loose); break; - case '!=': ret = neq(a, b, loose); break; - case '>': ret = gt(a, b, loose); break; - case '>=': ret = gte(a, b, loose); break; - case '<': ret = lt(a, b, loose); break; - case '<=': ret = lte(a, b, loose); break; - default: throw new TypeError('Invalid operator: ' + op); - } - return ret; -} - -exports.Comparator = Comparator; -function Comparator(comp, loose) { - if (comp instanceof Comparator) { - if (comp.loose === loose) - return comp; - else - comp = comp.value; - } - - if (!(this instanceof Comparator)) - return new Comparator(comp, loose); - - debug('comparator', comp, loose); - this.loose = loose; - this.parse(comp); - - if (this.semver === ANY) - this.value = ''; - else - this.value = this.operator + this.semver.version; - - debug('comp', this); -} - -var ANY = {}; -Comparator.prototype.parse = function(comp) { - var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; - var m = comp.match(r); - - if (!m) - throw new TypeError('Invalid comparator: ' + comp); - - this.operator = m[1]; - if (this.operator === '=') - this.operator = ''; - - // if it literally is just '>' or '' then allow anything. - if (!m[2]) - this.semver = ANY; - else - this.semver = new SemVer(m[2], this.loose); -}; - -Comparator.prototype.toString = function() { - return this.value; -}; - -Comparator.prototype.test = function(version) { - debug('Comparator.test', version, this.loose); - - if (this.semver === ANY) - return true; - - if (typeof version === 'string') - version = new SemVer(version, this.loose); - - return cmp(version, this.operator, this.semver, this.loose); -}; - -Comparator.prototype.intersects = function(comp, loose) { - if (!(comp instanceof Comparator)) { - throw new TypeError('a Comparator is required'); - } - - var rangeTmp; - - if (this.operator === '') { - rangeTmp = new Range(comp.value, loose); - return satisfies(this.value, rangeTmp, loose); - } else if (comp.operator === '') { - rangeTmp = new Range(this.value, loose); - return satisfies(comp.semver, rangeTmp, loose); - } - - var sameDirectionIncreasing = - (this.operator === '>=' || this.operator === '>') && - (comp.operator === '>=' || comp.operator === '>'); - var sameDirectionDecreasing = - (this.operator === '<=' || this.operator === '<') && - (comp.operator === '<=' || comp.operator === '<'); - var sameSemVer = this.semver.version === comp.semver.version; - var differentDirectionsInclusive = - (this.operator === '>=' || this.operator === '<=') && - (comp.operator === '>=' || comp.operator === '<='); - var oppositeDirectionsLessThan = - cmp(this.semver, '<', comp.semver, loose) && - ((this.operator === '>=' || this.operator === '>') && - (comp.operator === '<=' || comp.operator === '<')); - var oppositeDirectionsGreaterThan = - cmp(this.semver, '>', comp.semver, loose) && - ((this.operator === '<=' || this.operator === '<') && - (comp.operator === '>=' || comp.operator === '>')); - - return sameDirectionIncreasing || sameDirectionDecreasing || - (sameSemVer && differentDirectionsInclusive) || - oppositeDirectionsLessThan || oppositeDirectionsGreaterThan; -}; - - -exports.Range = Range; -function Range(range, loose) { - if (range instanceof Range) { - if (range.loose === loose) { - return range; - } else { - return new Range(range.raw, loose); - } - } - - if (range instanceof Comparator) { - return new Range(range.value, loose); - } - - if (!(this instanceof Range)) - return new Range(range, loose); - - this.loose = loose; - - // First, split based on boolean or || - this.raw = range; - this.set = range.split(/\s*\|\|\s*/).map(function(range) { - return this.parseRange(range.trim()); - }, this).filter(function(c) { - // throw out any that are not relevant for whatever reason - return c.length; - }); - - if (!this.set.length) { - throw new TypeError('Invalid SemVer Range: ' + range); - } - - this.format(); -} - -Range.prototype.format = function() { - this.range = this.set.map(function(comps) { - return comps.join(' ').trim(); - }).join('||').trim(); - return this.range; -}; - -Range.prototype.toString = function() { - return this.range; -}; - -Range.prototype.parseRange = function(range) { - var loose = this.loose; - range = range.trim(); - debug('range', range, loose); - // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` - var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]; - range = range.replace(hr, hyphenReplace); - debug('hyphen replace', range); - // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` - range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace); - debug('comparator trim', range, re[COMPARATORTRIM]); - - // `~ 1.2.3` => `~1.2.3` - range = range.replace(re[TILDETRIM], tildeTrimReplace); - - // `^ 1.2.3` => `^1.2.3` - range = range.replace(re[CARETTRIM], caretTrimReplace); - - // normalize spaces - range = range.split(/\s+/).join(' '); - - // At this point, the range is completely trimmed and - // ready to be split into comparators. - - var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; - var set = range.split(' ').map(function(comp) { - return parseComparator(comp, loose); - }).join(' ').split(/\s+/); - if (this.loose) { - // in loose mode, throw out any that are not valid comparators - set = set.filter(function(comp) { - return !!comp.match(compRe); - }); - } - set = set.map(function(comp) { - return new Comparator(comp, loose); - }); - - return set; -}; - -Range.prototype.intersects = function(range, loose) { - if (!(range instanceof Range)) { - throw new TypeError('a Range is required'); - } - - return this.set.some(function(thisComparators) { - return thisComparators.every(function(thisComparator) { - return range.set.some(function(rangeComparators) { - return rangeComparators.every(function(rangeComparator) { - return thisComparator.intersects(rangeComparator, loose); - }); - }); - }); - }); -}; - -// Mostly just for testing and legacy API reasons -exports.toComparators = toComparators; -function toComparators(range, loose) { - return new Range(range, loose).set.map(function(comp) { - return comp.map(function(c) { - return c.value; - }).join(' ').trim().split(' '); - }); -} - -// comprised of xranges, tildes, stars, and gtlt's at this point. -// already replaced the hyphen ranges -// turn into a set of JUST comparators. -function parseComparator(comp, loose) { - debug('comp', comp); - comp = replaceCarets(comp, loose); - debug('caret', comp); - comp = replaceTildes(comp, loose); - debug('tildes', comp); - comp = replaceXRanges(comp, loose); - debug('xrange', comp); - comp = replaceStars(comp, loose); - debug('stars', comp); - return comp; -} - -function isX(id) { - return !id || id.toLowerCase() === 'x' || id === '*'; -} - -// ~, ~> --> * (any, kinda silly) -// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 -// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 -// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 -// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 -// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 -function replaceTildes(comp, loose) { - return comp.trim().split(/\s+/).map(function(comp) { - return replaceTilde(comp, loose); - }).join(' '); -} - -function replaceTilde(comp, loose) { - var r = loose ? re[TILDELOOSE] : re[TILDE]; - return comp.replace(r, function(_, M, m, p, pr) { - debug('tilde', comp, _, M, m, p, pr); - var ret; - - if (isX(M)) - ret = ''; - else if (isX(m)) - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - else if (isX(p)) - // ~1.2 == >=1.2.0 <1.3.0 - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - else if (pr) { - debug('replaceTilde pr', pr); - if (pr.charAt(0) !== '-') - pr = '-' + pr; - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - // ~1.2.3 == >=1.2.3 <1.3.0 - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0'; - - debug('tilde return', ret); - return ret; - }); -} - -// ^ --> * (any, kinda silly) -// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 -// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 -// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 -// ^1.2.3 --> >=1.2.3 <2.0.0 -// ^1.2.0 --> >=1.2.0 <2.0.0 -function replaceCarets(comp, loose) { - return comp.trim().split(/\s+/).map(function(comp) { - return replaceCaret(comp, loose); - }).join(' '); -} - -function replaceCaret(comp, loose) { - debug('caret', comp, loose); - var r = loose ? re[CARETLOOSE] : re[CARET]; - return comp.replace(r, function(_, M, m, p, pr) { - debug('caret', comp, _, M, m, p, pr); - var ret; - - if (isX(M)) - ret = ''; - else if (isX(m)) - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - else if (isX(p)) { - if (M === '0') - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - else - ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'; - } else if (pr) { - debug('replaceCaret pr', pr); - if (pr.charAt(0) !== '-') - pr = '-' + pr; - if (M === '0') { - if (m === '0') - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + m + '.' + (+p + 1); - else - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + (+M + 1) + '.0.0'; - } else { - debug('no pr'); - if (M === '0') { - if (m === '0') - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + m + '.' + (+p + 1); - else - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - ret = '>=' + M + '.' + m + '.' + p + - ' <' + (+M + 1) + '.0.0'; - } - - debug('caret return', ret); - return ret; - }); -} - -function replaceXRanges(comp, loose) { - debug('replaceXRanges', comp, loose); - return comp.split(/\s+/).map(function(comp) { - return replaceXRange(comp, loose); - }).join(' '); -} - -function replaceXRange(comp, loose) { - comp = comp.trim(); - var r = loose ? re[XRANGELOOSE] : re[XRANGE]; - return comp.replace(r, function(ret, gtlt, M, m, p, pr) { - debug('xRange', comp, ret, gtlt, M, m, p, pr); - var xM = isX(M); - var xm = xM || isX(m); - var xp = xm || isX(p); - var anyX = xp; - - if (gtlt === '=' && anyX) - gtlt = ''; - - if (xM) { - if (gtlt === '>' || gtlt === '<') { - // nothing is allowed - ret = '<0.0.0'; - } else { - // nothing is forbidden - ret = '*'; - } - } else if (gtlt && anyX) { - // replace X with 0 - if (xm) - m = 0; - if (xp) - p = 0; - - if (gtlt === '>') { - // >1 => >=2.0.0 - // >1.2 => >=1.3.0 - // >1.2.3 => >= 1.2.4 - gtlt = '>='; - if (xm) { - M = +M + 1; - m = 0; - p = 0; - } else if (xp) { - m = +m + 1; - p = 0; - } - } else if (gtlt === '<=') { - // <=0.7.x is actually <0.8.0, since any 0.7.x should - // pass. Similarly, <=7.x is actually <8.0.0, etc. - gtlt = '<'; - if (xm) - M = +M + 1; - else - m = +m + 1; - } - - ret = gtlt + M + '.' + m + '.' + p; - } else if (xm) { - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - } else if (xp) { - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - } - - debug('xRange return', ret); - - return ret; - }); -} - -// Because * is AND-ed with everything else in the comparator, -// and '' means "any version", just remove the *s entirely. -function replaceStars(comp, loose) { - debug('replaceStars', comp, loose); - // Looseness is ignored here. star is always as loose as it gets! - return comp.trim().replace(re[STAR], ''); -} - -// This function is passed to string.replace(re[HYPHENRANGE]) -// M, m, patch, prerelease, build -// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 -// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do -// 1.2 - 3.4 => >=1.2.0 <3.5.0 -function hyphenReplace($0, - from, fM, fm, fp, fpr, fb, - to, tM, tm, tp, tpr, tb) { - - if (isX(fM)) - from = ''; - else if (isX(fm)) - from = '>=' + fM + '.0.0'; - else if (isX(fp)) - from = '>=' + fM + '.' + fm + '.0'; - else - from = '>=' + from; - - if (isX(tM)) - to = ''; - else if (isX(tm)) - to = '<' + (+tM + 1) + '.0.0'; - else if (isX(tp)) - to = '<' + tM + '.' + (+tm + 1) + '.0'; - else if (tpr) - to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr; - else - to = '<=' + to; - - return (from + ' ' + to).trim(); -} - - -// if ANY of the sets match ALL of its comparators, then pass -Range.prototype.test = function(version) { - if (!version) - return false; - - if (typeof version === 'string') - version = new SemVer(version, this.loose); - - for (var i = 0; i < this.set.length; i++) { - if (testSet(this.set[i], version)) - return true; - } - return false; -}; - -function testSet(set, version) { - for (var i = 0; i < set.length; i++) { - if (!set[i].test(version)) - return false; - } - - if (version.prerelease.length) { - // Find the set of versions that are allowed to have prereleases - // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 - // That should allow `1.2.3-pr.2` to pass. - // However, `1.2.4-alpha.notready` should NOT be allowed, - // even though it's within the range set by the comparators. - for (var i = 0; i < set.length; i++) { - debug(set[i].semver); - if (set[i].semver === ANY) - continue; - - if (set[i].semver.prerelease.length > 0) { - var allowed = set[i].semver; - if (allowed.major === version.major && - allowed.minor === version.minor && - allowed.patch === version.patch) - return true; - } - } - - // Version has a -pre, but it's not one of the ones we like. - return false; - } - - return true; -} - -exports.satisfies = satisfies; -function satisfies(version, range, loose) { - try { - range = new Range(range, loose); - } catch (er) { - return false; - } - return range.test(version); -} - -exports.maxSatisfying = maxSatisfying; -function maxSatisfying(versions, range, loose) { - var max = null; - var maxSV = null; - try { - var rangeObj = new Range(range, loose); - } catch (er) { - return null; - } - versions.forEach(function (v) { - if (rangeObj.test(v)) { // satisfies(v, range, loose) - if (!max || maxSV.compare(v) === -1) { // compare(max, v, true) - max = v; - maxSV = new SemVer(max, loose); - } - } - }) - return max; -} - -exports.minSatisfying = minSatisfying; -function minSatisfying(versions, range, loose) { - var min = null; - var minSV = null; - try { - var rangeObj = new Range(range, loose); - } catch (er) { - return null; - } - versions.forEach(function (v) { - if (rangeObj.test(v)) { // satisfies(v, range, loose) - if (!min || minSV.compare(v) === 1) { // compare(min, v, true) - min = v; - minSV = new SemVer(min, loose); - } - } - }) - return min; -} - -exports.validRange = validRange; -function validRange(range, loose) { - try { - // Return '*' instead of '' so that truthiness works. - // This will throw if it's invalid anyway - return new Range(range, loose).range || '*'; - } catch (er) { - return null; - } -} - -// Determine if version is less than all the versions possible in the range -exports.ltr = ltr; -function ltr(version, range, loose) { - return outside(version, range, '<', loose); -} - -// Determine if version is greater than all the versions possible in the range. -exports.gtr = gtr; -function gtr(version, range, loose) { - return outside(version, range, '>', loose); -} - -exports.outside = outside; -function outside(version, range, hilo, loose) { - version = new SemVer(version, loose); - range = new Range(range, loose); - - var gtfn, ltefn, ltfn, comp, ecomp; - switch (hilo) { - case '>': - gtfn = gt; - ltefn = lte; - ltfn = lt; - comp = '>'; - ecomp = '>='; - break; - case '<': - gtfn = lt; - ltefn = gte; - ltfn = gt; - comp = '<'; - ecomp = '<='; - break; - default: - throw new TypeError('Must provide a hilo val of "<" or ">"'); - } - - // If it satisifes the range it is not outside - if (satisfies(version, range, loose)) { - return false; - } - - // From now on, variable terms are as if we're in "gtr" mode. - // but note that everything is flipped for the "ltr" function. - - for (var i = 0; i < range.set.length; ++i) { - var comparators = range.set[i]; - - var high = null; - var low = null; - - comparators.forEach(function(comparator) { - if (comparator.semver === ANY) { - comparator = new Comparator('>=0.0.0') - } - high = high || comparator; - low = low || comparator; - if (gtfn(comparator.semver, high.semver, loose)) { - high = comparator; - } else if (ltfn(comparator.semver, low.semver, loose)) { - low = comparator; - } - }); - - // If the edge version comparator has a operator then our version - // isn't outside it - if (high.operator === comp || high.operator === ecomp) { - return false; - } - - // If the lowest version comparator has an operator and our version - // is less than it then it isn't higher than the range - if ((!low.operator || low.operator === comp) && - ltefn(version, low.semver)) { - return false; - } else if (low.operator === ecomp && ltfn(version, low.semver)) { - return false; - } - } - return true; -} - -exports.prerelease = prerelease; -function prerelease(version, loose) { - var parsed = parse(version, loose); - return (parsed && parsed.prerelease.length) ? parsed.prerelease : null; -} - -exports.intersects = intersects; -function intersects(r1, r2, loose) { - r1 = new Range(r1, loose) - r2 = new Range(r2, loose) - return r1.intersects(r2) -} - -exports.coerce = coerce; -function coerce(version) { - if (version instanceof SemVer) - return version; - - if (typeof version !== 'string') - return null; - - var match = version.match(re[COERCE]); - - if (match == null) - return null; - - return parse((match[1] || '0') + '.' + (match[2] || '0') + '.' + (match[3] || '0')); -} - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = require("stream"); - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -module.exports = require("url"); - -/***/ }), -/* 25 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscription; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_isArray__ = __webpack_require__(41); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isObject__ = __webpack_require__(444); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_isFunction__ = __webpack_require__(154); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_tryCatch__ = __webpack_require__(56); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_errorObject__ = __webpack_require__(48); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__ = __webpack_require__(441); -/** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_tryCatch,_util_errorObject,_util_UnsubscriptionError PURE_IMPORTS_END */ - - - - - - -var Subscription = /*@__PURE__*/ (function () { - function Subscription(unsubscribe) { - this.closed = false; - this._parent = null; - this._parents = null; - this._subscriptions = null; - if (unsubscribe) { - this._unsubscribe = unsubscribe; - } - } - Subscription.prototype.unsubscribe = function () { - var hasErrors = false; - var errors; - if (this.closed) { - return; - } - var _a = this, _parent = _a._parent, _parents = _a._parents, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions; - this.closed = true; - this._parent = null; - this._parents = null; - this._subscriptions = null; - var index = -1; - var len = _parents ? _parents.length : 0; - while (_parent) { - _parent.remove(this); - _parent = ++index < len && _parents[index] || null; - } - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__util_isFunction__["a" /* isFunction */])(_unsubscribe)) { - var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(_unsubscribe).call(this); - if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { - hasErrors = true; - errors = errors || (__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */] ? - flattenUnsubscriptionErrors(__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e.errors) : [__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e]); - } - } - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_isArray__["a" /* isArray */])(_subscriptions)) { - index = -1; - len = _subscriptions.length; - while (++index < len) { - var sub = _subscriptions[index]; - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isObject__["a" /* isObject */])(sub)) { - var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(sub.unsubscribe).call(sub); - if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { - hasErrors = true; - errors = errors || []; - var err = __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e; - if (err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) { - errors = errors.concat(flattenUnsubscriptionErrors(err.errors)); - } - else { - errors.push(err); - } - } - } - } - } - if (hasErrors) { - throw new __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */](errors); - } - }; - Subscription.prototype.add = function (teardown) { - if (!teardown || (teardown === Subscription.EMPTY)) { - return Subscription.EMPTY; - } - if (teardown === this) { - return this; - } - var subscription = teardown; - switch (typeof teardown) { - case 'function': - subscription = new Subscription(teardown); - case 'object': - if (subscription.closed || typeof subscription.unsubscribe !== 'function') { - return subscription; - } - else if (this.closed) { - subscription.unsubscribe(); - return subscription; - } - else if (typeof subscription._addParent !== 'function') { - var tmp = subscription; - subscription = new Subscription(); - subscription._subscriptions = [tmp]; - } - break; - default: - throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.'); - } - var subscriptions = this._subscriptions || (this._subscriptions = []); - subscriptions.push(subscription); - subscription._addParent(this); - return subscription; - }; - Subscription.prototype.remove = function (subscription) { - var subscriptions = this._subscriptions; - if (subscriptions) { - var subscriptionIndex = subscriptions.indexOf(subscription); - if (subscriptionIndex !== -1) { - subscriptions.splice(subscriptionIndex, 1); - } - } - }; - Subscription.prototype._addParent = function (parent) { - var _a = this, _parent = _a._parent, _parents = _a._parents; - if (!_parent || _parent === parent) { - this._parent = parent; - } - else if (!_parents) { - this._parents = [parent]; - } - else if (_parents.indexOf(parent) === -1) { - _parents.push(parent); - } - }; - Subscription.EMPTY = (function (empty) { - empty.closed = true; - return empty; - }(new Subscription())); - return Subscription; -}()); - -function flattenUnsubscriptionErrors(errors) { - return errors.reduce(function (errs, err) { return errs.concat((err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) ? err.errors : err); }, []); -} -//# sourceMappingURL=Subscription.js.map - - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2015 Joyent, Inc. - -module.exports = { - bufferSplit: bufferSplit, - addRSAMissing: addRSAMissing, - calculateDSAPublic: calculateDSAPublic, - calculateED25519Public: calculateED25519Public, - calculateX25519Public: calculateX25519Public, - mpNormalize: mpNormalize, - mpDenormalize: mpDenormalize, - ecNormalize: ecNormalize, - countZeros: countZeros, - assertCompatible: assertCompatible, - isCompatible: isCompatible, - opensslKeyDeriv: opensslKeyDeriv, - opensshCipherInfo: opensshCipherInfo, - publicFromPrivateECDSA: publicFromPrivateECDSA, - zeroPadToLength: zeroPadToLength, - writeBitString: writeBitString, - readBitString: readBitString -}; - -var assert = __webpack_require__(16); -var Buffer = __webpack_require__(15).Buffer; -var PrivateKey = __webpack_require__(33); -var Key = __webpack_require__(27); -var crypto = __webpack_require__(11); -var algs = __webpack_require__(32); -var asn1 = __webpack_require__(66); - -var ec, jsbn; -var nacl; - -var MAX_CLASS_DEPTH = 3; - -function isCompatible(obj, klass, needVer) { - if (obj === null || typeof (obj) !== 'object') - return (false); - if (needVer === undefined) - needVer = klass.prototype._sshpkApiVersion; - if (obj instanceof klass && - klass.prototype._sshpkApiVersion[0] == needVer[0]) - return (true); - var proto = Object.getPrototypeOf(obj); - var depth = 0; - while (proto.constructor.name !== klass.name) { - proto = Object.getPrototypeOf(proto); - if (!proto || ++depth > MAX_CLASS_DEPTH) - return (false); - } - if (proto.constructor.name !== klass.name) - return (false); - var ver = proto._sshpkApiVersion; - if (ver === undefined) - ver = klass._oldVersionDetect(obj); - if (ver[0] != needVer[0] || ver[1] < needVer[1]) - return (false); - return (true); -} - -function assertCompatible(obj, klass, needVer, name) { - if (name === undefined) - name = 'object'; - assert.ok(obj, name + ' must not be null'); - assert.object(obj, name + ' must be an object'); - if (needVer === undefined) - needVer = klass.prototype._sshpkApiVersion; - if (obj instanceof klass && - klass.prototype._sshpkApiVersion[0] == needVer[0]) - return; - var proto = Object.getPrototypeOf(obj); - var depth = 0; - while (proto.constructor.name !== klass.name) { - proto = Object.getPrototypeOf(proto); - assert.ok(proto && ++depth <= MAX_CLASS_DEPTH, - name + ' must be a ' + klass.name + ' instance'); - } - assert.strictEqual(proto.constructor.name, klass.name, - name + ' must be a ' + klass.name + ' instance'); - var ver = proto._sshpkApiVersion; - if (ver === undefined) - ver = klass._oldVersionDetect(obj); - assert.ok(ver[0] == needVer[0] && ver[1] >= needVer[1], - name + ' must be compatible with ' + klass.name + ' klass ' + - 'version ' + needVer[0] + '.' + needVer[1]); -} - -var CIPHER_LEN = { - 'des-ede3-cbc': { key: 7, iv: 8 }, - 'aes-128-cbc': { key: 16, iv: 16 } -}; -var PKCS5_SALT_LEN = 8; - -function opensslKeyDeriv(cipher, salt, passphrase, count) { - assert.buffer(salt, 'salt'); - assert.buffer(passphrase, 'passphrase'); - assert.number(count, 'iteration count'); - - var clen = CIPHER_LEN[cipher]; - assert.object(clen, 'supported cipher'); - - salt = salt.slice(0, PKCS5_SALT_LEN); - - var D, D_prev, bufs; - var material = Buffer.alloc(0); - while (material.length < clen.key + clen.iv) { - bufs = []; - if (D_prev) - bufs.push(D_prev); - bufs.push(passphrase); - bufs.push(salt); - D = Buffer.concat(bufs); - for (var j = 0; j < count; ++j) - D = crypto.createHash('md5').update(D).digest(); - material = Buffer.concat([material, D]); - D_prev = D; - } - - return ({ - key: material.slice(0, clen.key), - iv: material.slice(clen.key, clen.key + clen.iv) - }); -} - -/* Count leading zero bits on a buffer */ -function countZeros(buf) { - var o = 0, obit = 8; - while (o < buf.length) { - var mask = (1 << obit); - if ((buf[o] & mask) === mask) - break; - obit--; - if (obit < 0) { - o++; - obit = 8; - } - } - return (o*8 + (8 - obit) - 1); -} - -function bufferSplit(buf, chr) { - assert.buffer(buf); - assert.string(chr); - - var parts = []; - var lastPart = 0; - var matches = 0; - for (var i = 0; i < buf.length; ++i) { - if (buf[i] === chr.charCodeAt(matches)) - ++matches; - else if (buf[i] === chr.charCodeAt(0)) - matches = 1; - else - matches = 0; - - if (matches >= chr.length) { - var newPart = i + 1; - parts.push(buf.slice(lastPart, newPart - matches)); - lastPart = newPart; - matches = 0; - } - } - if (lastPart <= buf.length) - parts.push(buf.slice(lastPart, buf.length)); - - return (parts); -} - -function ecNormalize(buf, addZero) { - assert.buffer(buf); - if (buf[0] === 0x00 && buf[1] === 0x04) { - if (addZero) - return (buf); - return (buf.slice(1)); - } else if (buf[0] === 0x04) { - if (!addZero) - return (buf); - } else { - while (buf[0] === 0x00) - buf = buf.slice(1); - if (buf[0] === 0x02 || buf[0] === 0x03) - throw (new Error('Compressed elliptic curve points ' + - 'are not supported')); - if (buf[0] !== 0x04) - throw (new Error('Not a valid elliptic curve point')); - if (!addZero) - return (buf); - } - var b = Buffer.alloc(buf.length + 1); - b[0] = 0x0; - buf.copy(b, 1); - return (b); -} - -function readBitString(der, tag) { - if (tag === undefined) - tag = asn1.Ber.BitString; - var buf = der.readString(tag, true); - assert.strictEqual(buf[0], 0x00, 'bit strings with unused bits are ' + - 'not supported (0x' + buf[0].toString(16) + ')'); - return (buf.slice(1)); -} - -function writeBitString(der, buf, tag) { - if (tag === undefined) - tag = asn1.Ber.BitString; - var b = Buffer.alloc(buf.length + 1); - b[0] = 0x00; - buf.copy(b, 1); - der.writeBuffer(b, tag); -} - -function mpNormalize(buf) { - assert.buffer(buf); - while (buf.length > 1 && buf[0] === 0x00 && (buf[1] & 0x80) === 0x00) - buf = buf.slice(1); - if ((buf[0] & 0x80) === 0x80) { - var b = Buffer.alloc(buf.length + 1); - b[0] = 0x00; - buf.copy(b, 1); - buf = b; - } - return (buf); -} - -function mpDenormalize(buf) { - assert.buffer(buf); - while (buf.length > 1 && buf[0] === 0x00) - buf = buf.slice(1); - return (buf); -} - -function zeroPadToLength(buf, len) { - assert.buffer(buf); - assert.number(len); - while (buf.length > len) { - assert.equal(buf[0], 0x00); - buf = buf.slice(1); - } - while (buf.length < len) { - var b = Buffer.alloc(buf.length + 1); - b[0] = 0x00; - buf.copy(b, 1); - buf = b; - } - return (buf); -} - -function bigintToMpBuf(bigint) { - var buf = Buffer.from(bigint.toByteArray()); - buf = mpNormalize(buf); - return (buf); -} - -function calculateDSAPublic(g, p, x) { - assert.buffer(g); - assert.buffer(p); - assert.buffer(x); - try { - var bigInt = __webpack_require__(81).BigInteger; - } catch (e) { - throw (new Error('To load a PKCS#8 format DSA private key, ' + - 'the node jsbn library is required.')); - } - g = new bigInt(g); - p = new bigInt(p); - x = new bigInt(x); - var y = g.modPow(x, p); - var ybuf = bigintToMpBuf(y); - return (ybuf); -} - -function calculateED25519Public(k) { - assert.buffer(k); - - if (nacl === undefined) - nacl = __webpack_require__(76); - - var kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k)); - return (Buffer.from(kp.publicKey)); -} - -function calculateX25519Public(k) { - assert.buffer(k); - - if (nacl === undefined) - nacl = __webpack_require__(76); - - var kp = nacl.box.keyPair.fromSeed(new Uint8Array(k)); - return (Buffer.from(kp.publicKey)); -} - -function addRSAMissing(key) { - assert.object(key); - assertCompatible(key, PrivateKey, [1, 1]); - try { - var bigInt = __webpack_require__(81).BigInteger; - } catch (e) { - throw (new Error('To write a PEM private key from ' + - 'this source, the node jsbn lib is required.')); - } - - var d = new bigInt(key.part.d.data); - var buf; - - if (!key.part.dmodp) { - var p = new bigInt(key.part.p.data); - var dmodp = d.mod(p.subtract(1)); - - buf = bigintToMpBuf(dmodp); - key.part.dmodp = {name: 'dmodp', data: buf}; - key.parts.push(key.part.dmodp); - } - if (!key.part.dmodq) { - var q = new bigInt(key.part.q.data); - var dmodq = d.mod(q.subtract(1)); - - buf = bigintToMpBuf(dmodq); - key.part.dmodq = {name: 'dmodq', data: buf}; - key.parts.push(key.part.dmodq); - } -} - -function publicFromPrivateECDSA(curveName, priv) { - assert.string(curveName, 'curveName'); - assert.buffer(priv); - if (ec === undefined) - ec = __webpack_require__(139); - if (jsbn === undefined) - jsbn = __webpack_require__(81).BigInteger; - var params = algs.curves[curveName]; - var p = new jsbn(params.p); - var a = new jsbn(params.a); - var b = new jsbn(params.b); - var curve = new ec.ECCurveFp(p, a, b); - var G = curve.decodePointHex(params.G.toString('hex')); - - var d = new jsbn(mpNormalize(priv)); - var pub = G.multiply(d); - pub = Buffer.from(curve.encodePointHex(pub), 'hex'); - - var parts = []; - parts.push({name: 'curve', data: Buffer.from(curveName)}); - parts.push({name: 'Q', data: pub}); - - var key = new Key({type: 'ecdsa', curve: curve, parts: parts}); - return (key); -} - -function opensshCipherInfo(cipher) { - var inf = {}; - switch (cipher) { - case '3des-cbc': - inf.keySize = 24; - inf.blockSize = 8; - inf.opensslName = 'des-ede3-cbc'; - break; - case 'blowfish-cbc': - inf.keySize = 16; - inf.blockSize = 8; - inf.opensslName = 'bf-cbc'; - break; - case 'aes128-cbc': - case 'aes128-ctr': - case 'aes128-gcm@openssh.com': - inf.keySize = 16; - inf.blockSize = 16; - inf.opensslName = 'aes-128-' + cipher.slice(7, 10); - break; - case 'aes192-cbc': - case 'aes192-ctr': - case 'aes192-gcm@openssh.com': - inf.keySize = 24; - inf.blockSize = 16; - inf.opensslName = 'aes-192-' + cipher.slice(7, 10); - break; - case 'aes256-cbc': - case 'aes256-ctr': - case 'aes256-gcm@openssh.com': - inf.keySize = 32; - inf.blockSize = 16; - inf.opensslName = 'aes-256-' + cipher.slice(7, 10); - break; - default: - throw (new Error( - 'Unsupported openssl cipher "' + cipher + '"')); - } - return (inf); -} - - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2017 Joyent, Inc. - -module.exports = Key; - -var assert = __webpack_require__(16); -var algs = __webpack_require__(32); -var crypto = __webpack_require__(11); -var Fingerprint = __webpack_require__(156); -var Signature = __webpack_require__(75); -var DiffieHellman = __webpack_require__(325).DiffieHellman; -var errs = __webpack_require__(74); -var utils = __webpack_require__(26); -var PrivateKey = __webpack_require__(33); -var edCompat; - -try { - edCompat = __webpack_require__(454); -} catch (e) { - /* Just continue through, and bail out if we try to use it. */ -} - -var InvalidAlgorithmError = errs.InvalidAlgorithmError; -var KeyParseError = errs.KeyParseError; - -var formats = {}; -formats['auto'] = __webpack_require__(455); -formats['pem'] = __webpack_require__(86); -formats['pkcs1'] = __webpack_require__(327); -formats['pkcs8'] = __webpack_require__(157); -formats['rfc4253'] = __webpack_require__(103); -formats['ssh'] = __webpack_require__(456); -formats['ssh-private'] = __webpack_require__(192); -formats['openssh'] = formats['ssh-private']; -formats['dnssec'] = __webpack_require__(326); - -function Key(opts) { - assert.object(opts, 'options'); - assert.arrayOfObject(opts.parts, 'options.parts'); - assert.string(opts.type, 'options.type'); - assert.optionalString(opts.comment, 'options.comment'); - - var algInfo = algs.info[opts.type]; - if (typeof (algInfo) !== 'object') - throw (new InvalidAlgorithmError(opts.type)); - - var partLookup = {}; - for (var i = 0; i < opts.parts.length; ++i) { - var part = opts.parts[i]; - partLookup[part.name] = part; - } - - this.type = opts.type; - this.parts = opts.parts; - this.part = partLookup; - this.comment = undefined; - this.source = opts.source; - - /* for speeding up hashing/fingerprint operations */ - this._rfc4253Cache = opts._rfc4253Cache; - this._hashCache = {}; - - var sz; - this.curve = undefined; - if (this.type === 'ecdsa') { - var curve = this.part.curve.data.toString(); - this.curve = curve; - sz = algs.curves[curve].size; - } else if (this.type === 'ed25519' || this.type === 'curve25519') { - sz = 256; - this.curve = 'curve25519'; - } else { - var szPart = this.part[algInfo.sizePart]; - sz = szPart.data.length; - sz = sz * 8 - utils.countZeros(szPart.data); - } - this.size = sz; -} - -Key.formats = formats; - -Key.prototype.toBuffer = function (format, options) { - if (format === undefined) - format = 'ssh'; - assert.string(format, 'format'); - assert.object(formats[format], 'formats[format]'); - assert.optionalObject(options, 'options'); - - if (format === 'rfc4253') { - if (this._rfc4253Cache === undefined) - this._rfc4253Cache = formats['rfc4253'].write(this); - return (this._rfc4253Cache); - } - - return (formats[format].write(this, options)); -}; - -Key.prototype.toString = function (format, options) { - return (this.toBuffer(format, options).toString()); -}; - -Key.prototype.hash = function (algo) { - assert.string(algo, 'algorithm'); - algo = algo.toLowerCase(); - if (algs.hashAlgs[algo] === undefined) - throw (new InvalidAlgorithmError(algo)); - - if (this._hashCache[algo]) - return (this._hashCache[algo]); - var hash = crypto.createHash(algo). - update(this.toBuffer('rfc4253')).digest(); - this._hashCache[algo] = hash; - return (hash); -}; - -Key.prototype.fingerprint = function (algo) { - if (algo === undefined) - algo = 'sha256'; - assert.string(algo, 'algorithm'); - var opts = { - type: 'key', - hash: this.hash(algo), - algorithm: algo - }; - return (new Fingerprint(opts)); -}; - -Key.prototype.defaultHashAlgorithm = function () { - var hashAlgo = 'sha1'; - if (this.type === 'rsa') - hashAlgo = 'sha256'; - if (this.type === 'dsa' && this.size > 1024) - hashAlgo = 'sha256'; - if (this.type === 'ed25519') - hashAlgo = 'sha512'; - if (this.type === 'ecdsa') { - if (this.size <= 256) - hashAlgo = 'sha256'; - else if (this.size <= 384) - hashAlgo = 'sha384'; - else - hashAlgo = 'sha512'; - } - return (hashAlgo); -}; - -Key.prototype.createVerify = function (hashAlgo) { - if (hashAlgo === undefined) - hashAlgo = this.defaultHashAlgorithm(); - assert.string(hashAlgo, 'hash algorithm'); - - /* ED25519 is not supported by OpenSSL, use a javascript impl. */ - if (this.type === 'ed25519' && edCompat !== undefined) - return (new edCompat.Verifier(this, hashAlgo)); - if (this.type === 'curve25519') - throw (new Error('Curve25519 keys are not suitable for ' + - 'signing or verification')); - - var v, nm, err; - try { - nm = hashAlgo.toUpperCase(); - v = crypto.createVerify(nm); - } catch (e) { - err = e; - } - if (v === undefined || (err instanceof Error && - err.message.match(/Unknown message digest/))) { - nm = 'RSA-'; - nm += hashAlgo.toUpperCase(); - v = crypto.createVerify(nm); - } - assert.ok(v, 'failed to create verifier'); - var oldVerify = v.verify.bind(v); - var key = this.toBuffer('pkcs8'); - var curve = this.curve; - var self = this; - v.verify = function (signature, fmt) { - if (Signature.isSignature(signature, [2, 0])) { - if (signature.type !== self.type) - return (false); - if (signature.hashAlgorithm && - signature.hashAlgorithm !== hashAlgo) - return (false); - if (signature.curve && self.type === 'ecdsa' && - signature.curve !== curve) - return (false); - return (oldVerify(key, signature.toBuffer('asn1'))); - - } else if (typeof (signature) === 'string' || - Buffer.isBuffer(signature)) { - return (oldVerify(key, signature, fmt)); - - /* - * Avoid doing this on valid arguments, walking the prototype - * chain can be quite slow. - */ - } else if (Signature.isSignature(signature, [1, 0])) { - throw (new Error('signature was created by too old ' + - 'a version of sshpk and cannot be verified')); - - } else { - throw (new TypeError('signature must be a string, ' + - 'Buffer, or Signature object')); - } - }; - return (v); -}; - -Key.prototype.createDiffieHellman = function () { - if (this.type === 'rsa') - throw (new Error('RSA keys do not support Diffie-Hellman')); - - return (new DiffieHellman(this)); -}; -Key.prototype.createDH = Key.prototype.createDiffieHellman; - -Key.parse = function (data, format, options) { - if (typeof (data) !== 'string') - assert.buffer(data, 'data'); - if (format === undefined) - format = 'auto'; - assert.string(format, 'format'); - if (typeof (options) === 'string') - options = { filename: options }; - assert.optionalObject(options, 'options'); - if (options === undefined) - options = {}; - assert.optionalString(options.filename, 'options.filename'); - if (options.filename === undefined) - options.filename = '(unnamed)'; - - assert.object(formats[format], 'formats[format]'); - - try { - var k = formats[format].read(data, options); - if (k instanceof PrivateKey) - k = k.toPublic(); - if (!k.comment) - k.comment = options.filename; - return (k); - } catch (e) { - if (e.name === 'KeyEncryptedError') - throw (e); - throw (new KeyParseError(options.filename, format, e)); - } -}; - -Key.isKey = function (obj, ver) { - return (utils.isCompatible(obj, Key, ver)); -}; - -/* - * API versions for Key: - * [1,0] -- initial ver, may take Signature for createVerify or may not - * [1,1] -- added pkcs1, pkcs8 formats - * [1,2] -- added auto, ssh-private, openssh formats - * [1,3] -- added defaultHashAlgorithm - * [1,4] -- added ed support, createDH - * [1,5] -- first explicitly tagged version - * [1,6] -- changed ed25519 part names - */ -Key.prototype._sshpkApiVersion = [1, 6]; - -Key._oldVersionDetect = function (obj) { - assert.func(obj.toBuffer); - assert.func(obj.fingerprint); - if (obj.createDH) - return ([1, 4]); - if (obj.defaultHashAlgorithm) - return ([1, 3]); - if (obj.formats['auto']) - return ([1, 2]); - if (obj.formats['pkcs1']) - return ([1, 1]); - return ([1, 0]); -}; - - -/***/ }), -/* 28 */ -/***/ (function(module, exports) { - -module.exports = require("assert"); - -/***/ }), -/* 29 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = nullify; -function nullify(obj = {}) { - if (Array.isArray(obj)) { - for (var _iterator = obj, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref; - - if (_isArray) { - if (_i >= _iterator.length) break; - _ref = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref = _i.value; - } - - const item = _ref; - - nullify(item); - } - } else if (obj !== null && typeof obj === 'object' || typeof obj === 'function') { - Object.setPrototypeOf(obj, null); - - // for..in can only be applied to 'object', not 'function' - if (typeof obj === 'object') { - for (const key in obj) { - nullify(obj[key]); - } - } - } - - return obj; -} - -/***/ }), -/* 30 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const escapeStringRegexp = __webpack_require__(388); -const ansiStyles = __webpack_require__(506); -const stdoutColor = __webpack_require__(598).stdout; - -const template = __webpack_require__(599); - -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); - -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; - -// `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = new Set(['gray']); - -const styles = Object.create(null); - -function applyOptions(obj, options) { - options = options || {}; - - // Detect level if not set manually - const scLevel = stdoutColor ? stdoutColor.level : 0; - obj.level = options.level === undefined ? scLevel : options.level; - obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; -} - -function Chalk(options) { - // We check for this.template here since calling `chalk.constructor()` - // by itself will have a `this` of a previously constructed chalk object - if (!this || !(this instanceof Chalk) || this.template) { - const chalk = {}; - applyOptions(chalk, options); - - chalk.template = function () { - const args = [].slice.call(arguments); - return chalkTag.apply(null, [chalk.template].concat(args)); - }; - - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); - - chalk.template.constructor = Chalk; - - return chalk.template; - } - - applyOptions(this, options); -} - -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; -} - -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); - - styles[key] = { - get() { - const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); - } - }; -} - -styles.visible = { - get() { - return build.call(this, this._styles || [], true, 'visible'); - } -}; - -ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); -for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.has(model)) { - continue; - } - - styles[model] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.color.close, - closeRe: ansiStyles.color.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; - } - }; -} - -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } - - const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.bgColor.close, - closeRe: ansiStyles.bgColor.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; - } - }; -} - -const proto = Object.defineProperties(() => {}, styles); - -function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; - - builder._styles = _styles; - builder._empty = _empty; - - const self = this; - - Object.defineProperty(builder, 'level', { - enumerable: true, - get() { - return self.level; - }, - set(level) { - self.level = level; - } - }); - - Object.defineProperty(builder, 'enabled', { - enumerable: true, - get() { - return self.enabled; - }, - set(enabled) { - self.enabled = enabled; - } - }); - - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; - - // `__proto__` is used because we must return a function, but there is - // no way to create a function with a different prototype - builder.__proto__ = proto; // eslint-disable-line no-proto - - return builder; -} - -function applyStyle() { - // Support varags, but simply cast to string in case there's only one arg - const args = arguments; - const argsLen = args.length; - let str = String(arguments[0]); - - if (argsLen === 0) { - return ''; - } - - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; - } - } - - if (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; - } - - // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, - // see https://github.com/chalk/chalk/issues/58 - // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. - const originalDim = ansiStyles.dim.open; - if (isSimpleWindowsTerm && this.hasGrey) { - ansiStyles.dim.open = ''; - } - - for (const code of this._styles.slice().reverse()) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - str = code.open + str.replace(code.closeRe, code.open) + code.close; - - // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS - // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); - } - - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; - - return str; -} - -function chalkTag(chalk, strings) { - if (!Array.isArray(strings)) { - // If chalk() was called by itself or with a string, - // return the string itself as a string. - return [].slice.call(arguments, 1).join(' '); - } - - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[0]]; - - for (let i = 1; i < strings.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); - } - - return template(chalk, parts.join('')); -} - -Object.defineProperties(Chalk.prototype, styles); - -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript - - -/***/ }), -/* 31 */ -/***/ (function(module, exports) { - -var core = module.exports = { version: '2.5.7' }; -if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef - - -/***/ }), -/* 32 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2015 Joyent, Inc. - -var Buffer = __webpack_require__(15).Buffer; - -var algInfo = { - 'dsa': { - parts: ['p', 'q', 'g', 'y'], - sizePart: 'p' - }, - 'rsa': { - parts: ['e', 'n'], - sizePart: 'n' - }, - 'ecdsa': { - parts: ['curve', 'Q'], - sizePart: 'Q' - }, - 'ed25519': { - parts: ['A'], - sizePart: 'A' - } -}; -algInfo['curve25519'] = algInfo['ed25519']; - -var algPrivInfo = { - 'dsa': { - parts: ['p', 'q', 'g', 'y', 'x'] - }, - 'rsa': { - parts: ['n', 'e', 'd', 'iqmp', 'p', 'q'] - }, - 'ecdsa': { - parts: ['curve', 'Q', 'd'] - }, - 'ed25519': { - parts: ['A', 'k'] - } -}; -algPrivInfo['curve25519'] = algPrivInfo['ed25519']; - -var hashAlgs = { - 'md5': true, - 'sha1': true, - 'sha256': true, - 'sha384': true, - 'sha512': true -}; - -/* - * Taken from - * http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf - */ -var curves = { - 'nistp256': { - size: 256, - pkcs8oid: '1.2.840.10045.3.1.7', - p: Buffer.from(('00' + - 'ffffffff 00000001 00000000 00000000' + - '00000000 ffffffff ffffffff ffffffff'). - replace(/ /g, ''), 'hex'), - a: Buffer.from(('00' + - 'FFFFFFFF 00000001 00000000 00000000' + - '00000000 FFFFFFFF FFFFFFFF FFFFFFFC'). - replace(/ /g, ''), 'hex'), - b: Buffer.from(( - '5ac635d8 aa3a93e7 b3ebbd55 769886bc' + - '651d06b0 cc53b0f6 3bce3c3e 27d2604b'). - replace(/ /g, ''), 'hex'), - s: Buffer.from(('00' + - 'c49d3608 86e70493 6a6678e1 139d26b7' + - '819f7e90'). - replace(/ /g, ''), 'hex'), - n: Buffer.from(('00' + - 'ffffffff 00000000 ffffffff ffffffff' + - 'bce6faad a7179e84 f3b9cac2 fc632551'). - replace(/ /g, ''), 'hex'), - G: Buffer.from(('04' + - '6b17d1f2 e12c4247 f8bce6e5 63a440f2' + - '77037d81 2deb33a0 f4a13945 d898c296' + - '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16' + - '2bce3357 6b315ece cbb64068 37bf51f5'). - replace(/ /g, ''), 'hex') - }, - 'nistp384': { - size: 384, - pkcs8oid: '1.3.132.0.34', - p: Buffer.from(('00' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff fffffffe' + - 'ffffffff 00000000 00000000 ffffffff'). - replace(/ /g, ''), 'hex'), - a: Buffer.from(('00' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' + - 'FFFFFFFF 00000000 00000000 FFFFFFFC'). - replace(/ /g, ''), 'hex'), - b: Buffer.from(( - 'b3312fa7 e23ee7e4 988e056b e3f82d19' + - '181d9c6e fe814112 0314088f 5013875a' + - 'c656398d 8a2ed19d 2a85c8ed d3ec2aef'). - replace(/ /g, ''), 'hex'), - s: Buffer.from(('00' + - 'a335926a a319a27a 1d00896a 6773a482' + - '7acdac73'). - replace(/ /g, ''), 'hex'), - n: Buffer.from(('00' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff c7634d81 f4372ddf' + - '581a0db2 48b0a77a ecec196a ccc52973'). - replace(/ /g, ''), 'hex'), - G: Buffer.from(('04' + - 'aa87ca22 be8b0537 8eb1c71e f320ad74' + - '6e1d3b62 8ba79b98 59f741e0 82542a38' + - '5502f25d bf55296c 3a545e38 72760ab7' + - '3617de4a 96262c6f 5d9e98bf 9292dc29' + - 'f8f41dbd 289a147c e9da3113 b5f0b8c0' + - '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f'). - replace(/ /g, ''), 'hex') - }, - 'nistp521': { - size: 521, - pkcs8oid: '1.3.132.0.35', - p: Buffer.from(( - '01ffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffff').replace(/ /g, ''), 'hex'), - a: Buffer.from(('01FF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC'). - replace(/ /g, ''), 'hex'), - b: Buffer.from(('51' + - '953eb961 8e1c9a1f 929a21a0 b68540ee' + - 'a2da725b 99b315f3 b8b48991 8ef109e1' + - '56193951 ec7e937b 1652c0bd 3bb1bf07' + - '3573df88 3d2c34f1 ef451fd4 6b503f00'). - replace(/ /g, ''), 'hex'), - s: Buffer.from(('00' + - 'd09e8800 291cb853 96cc6717 393284aa' + - 'a0da64ba').replace(/ /g, ''), 'hex'), - n: Buffer.from(('01ff' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff fffffffa' + - '51868783 bf2f966b 7fcc0148 f709a5d0' + - '3bb5c9b8 899c47ae bb6fb71e 91386409'). - replace(/ /g, ''), 'hex'), - G: Buffer.from(('04' + - '00c6 858e06b7 0404e9cd 9e3ecb66 2395b442' + - '9c648139 053fb521 f828af60 6b4d3dba' + - 'a14b5e77 efe75928 fe1dc127 a2ffa8de' + - '3348b3c1 856a429b f97e7e31 c2e5bd66' + - '0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9' + - '98f54449 579b4468 17afbd17 273e662c' + - '97ee7299 5ef42640 c550b901 3fad0761' + - '353c7086 a272c240 88be9476 9fd16650'). - replace(/ /g, ''), 'hex') - } -}; - -module.exports = { - info: algInfo, - privInfo: algPrivInfo, - hashAlgs: hashAlgs, - curves: curves -}; - - -/***/ }), -/* 33 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2017 Joyent, Inc. - -module.exports = PrivateKey; - -var assert = __webpack_require__(16); -var Buffer = __webpack_require__(15).Buffer; -var algs = __webpack_require__(32); -var crypto = __webpack_require__(11); -var Fingerprint = __webpack_require__(156); -var Signature = __webpack_require__(75); -var errs = __webpack_require__(74); -var util = __webpack_require__(3); -var utils = __webpack_require__(26); -var dhe = __webpack_require__(325); -var generateECDSA = dhe.generateECDSA; -var generateED25519 = dhe.generateED25519; -var edCompat; -var nacl; - -try { - edCompat = __webpack_require__(454); -} catch (e) { - /* Just continue through, and bail out if we try to use it. */ -} - -var Key = __webpack_require__(27); - -var InvalidAlgorithmError = errs.InvalidAlgorithmError; -var KeyParseError = errs.KeyParseError; -var KeyEncryptedError = errs.KeyEncryptedError; - -var formats = {}; -formats['auto'] = __webpack_require__(455); -formats['pem'] = __webpack_require__(86); -formats['pkcs1'] = __webpack_require__(327); -formats['pkcs8'] = __webpack_require__(157); -formats['rfc4253'] = __webpack_require__(103); -formats['ssh-private'] = __webpack_require__(192); -formats['openssh'] = formats['ssh-private']; -formats['ssh'] = formats['ssh-private']; -formats['dnssec'] = __webpack_require__(326); - -function PrivateKey(opts) { - assert.object(opts, 'options'); - Key.call(this, opts); - - this._pubCache = undefined; -} -util.inherits(PrivateKey, Key); - -PrivateKey.formats = formats; - -PrivateKey.prototype.toBuffer = function (format, options) { - if (format === undefined) - format = 'pkcs1'; - assert.string(format, 'format'); - assert.object(formats[format], 'formats[format]'); - assert.optionalObject(options, 'options'); - - return (formats[format].write(this, options)); -}; - -PrivateKey.prototype.hash = function (algo) { - return (this.toPublic().hash(algo)); -}; - -PrivateKey.prototype.toPublic = function () { - if (this._pubCache) - return (this._pubCache); - - var algInfo = algs.info[this.type]; - var pubParts = []; - for (var i = 0; i < algInfo.parts.length; ++i) { - var p = algInfo.parts[i]; - pubParts.push(this.part[p]); - } - - this._pubCache = new Key({ - type: this.type, - source: this, - parts: pubParts - }); - if (this.comment) - this._pubCache.comment = this.comment; - return (this._pubCache); -}; - -PrivateKey.prototype.derive = function (newType) { - assert.string(newType, 'type'); - var priv, pub, pair; - - if (this.type === 'ed25519' && newType === 'curve25519') { - if (nacl === undefined) - nacl = __webpack_require__(76); - - priv = this.part.k.data; - if (priv[0] === 0x00) - priv = priv.slice(1); - - pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv)); - pub = Buffer.from(pair.publicKey); - - return (new PrivateKey({ - type: 'curve25519', - parts: [ - { name: 'A', data: utils.mpNormalize(pub) }, - { name: 'k', data: utils.mpNormalize(priv) } - ] - })); - } else if (this.type === 'curve25519' && newType === 'ed25519') { - if (nacl === undefined) - nacl = __webpack_require__(76); - - priv = this.part.k.data; - if (priv[0] === 0x00) - priv = priv.slice(1); - - pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv)); - pub = Buffer.from(pair.publicKey); - - return (new PrivateKey({ - type: 'ed25519', - parts: [ - { name: 'A', data: utils.mpNormalize(pub) }, - { name: 'k', data: utils.mpNormalize(priv) } - ] - })); - } - throw (new Error('Key derivation not supported from ' + this.type + - ' to ' + newType)); -}; - -PrivateKey.prototype.createVerify = function (hashAlgo) { - return (this.toPublic().createVerify(hashAlgo)); -}; - -PrivateKey.prototype.createSign = function (hashAlgo) { - if (hashAlgo === undefined) - hashAlgo = this.defaultHashAlgorithm(); - assert.string(hashAlgo, 'hash algorithm'); - - /* ED25519 is not supported by OpenSSL, use a javascript impl. */ - if (this.type === 'ed25519' && edCompat !== undefined) - return (new edCompat.Signer(this, hashAlgo)); - if (this.type === 'curve25519') - throw (new Error('Curve25519 keys are not suitable for ' + - 'signing or verification')); - - var v, nm, err; - try { - nm = hashAlgo.toUpperCase(); - v = crypto.createSign(nm); - } catch (e) { - err = e; - } - if (v === undefined || (err instanceof Error && - err.message.match(/Unknown message digest/))) { - nm = 'RSA-'; - nm += hashAlgo.toUpperCase(); - v = crypto.createSign(nm); - } - assert.ok(v, 'failed to create verifier'); - var oldSign = v.sign.bind(v); - var key = this.toBuffer('pkcs1'); - var type = this.type; - var curve = this.curve; - v.sign = function () { - var sig = oldSign(key); - if (typeof (sig) === 'string') - sig = Buffer.from(sig, 'binary'); - sig = Signature.parse(sig, type, 'asn1'); - sig.hashAlgorithm = hashAlgo; - sig.curve = curve; - return (sig); - }; - return (v); -}; - -PrivateKey.parse = function (data, format, options) { - if (typeof (data) !== 'string') - assert.buffer(data, 'data'); - if (format === undefined) - format = 'auto'; - assert.string(format, 'format'); - if (typeof (options) === 'string') - options = { filename: options }; - assert.optionalObject(options, 'options'); - if (options === undefined) - options = {}; - assert.optionalString(options.filename, 'options.filename'); - if (options.filename === undefined) - options.filename = '(unnamed)'; - - assert.object(formats[format], 'formats[format]'); - - try { - var k = formats[format].read(data, options); - assert.ok(k instanceof PrivateKey, 'key is not a private key'); - if (!k.comment) - k.comment = options.filename; - return (k); - } catch (e) { - if (e.name === 'KeyEncryptedError') - throw (e); - throw (new KeyParseError(options.filename, format, e)); - } -}; - -PrivateKey.isPrivateKey = function (obj, ver) { - return (utils.isCompatible(obj, PrivateKey, ver)); -}; - -PrivateKey.generate = function (type, options) { - if (options === undefined) - options = {}; - assert.object(options, 'options'); - - switch (type) { - case 'ecdsa': - if (options.curve === undefined) - options.curve = 'nistp256'; - assert.string(options.curve, 'options.curve'); - return (generateECDSA(options.curve)); - case 'ed25519': - return (generateED25519()); - default: - throw (new Error('Key generation not supported with key ' + - 'type "' + type + '"')); - } -}; - -/* - * API versions for PrivateKey: - * [1,0] -- initial ver - * [1,1] -- added auto, pkcs[18], openssh/ssh-private formats - * [1,2] -- added defaultHashAlgorithm - * [1,3] -- added derive, ed, createDH - * [1,4] -- first tagged version - * [1,5] -- changed ed25519 part names and format - */ -PrivateKey.prototype._sshpkApiVersion = [1, 5]; - -PrivateKey._oldVersionDetect = function (obj) { - assert.func(obj.toPublic); - assert.func(obj.createSign); - if (obj.derive) - return ([1, 3]); - if (obj.defaultHashAlgorithm) - return ([1, 2]); - if (obj.formats['auto']) - return ([1, 1]); - return ([1, 0]); -}; - - -/***/ }), -/* 34 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.wrapLifecycle = exports.run = exports.install = exports.Install = undefined; - -var _extends2; - -function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); -} - -var _asyncToGenerator2; - -function _load_asyncToGenerator() { - return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); -} - -let install = exports.install = (() => { - var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, lockfile) { - yield wrapLifecycle(config, flags, (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const install = new Install(flags, config, reporter, lockfile); - yield install.init(); - })); - }); - - return function install(_x7, _x8, _x9, _x10) { - return _ref29.apply(this, arguments); - }; -})(); - -let run = exports.run = (() => { - var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - let lockfile; - let error = 'installCommandRenamed'; - if (flags.lockfile === false) { - lockfile = new (_lockfile || _load_lockfile()).default(); - } else { - lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.lockfileFolder, reporter); - } - - if (args.length) { - const exampleArgs = args.slice(); - - if (flags.saveDev) { - exampleArgs.push('--dev'); - } - if (flags.savePeer) { - exampleArgs.push('--peer'); - } - if (flags.saveOptional) { - exampleArgs.push('--optional'); - } - if (flags.saveExact) { - exampleArgs.push('--exact'); - } - if (flags.saveTilde) { - exampleArgs.push('--tilde'); - } - let command = 'add'; - if (flags.global) { - error = 'globalFlagRemoved'; - command = 'global add'; - } - throw new (_errors || _load_errors()).MessageError(reporter.lang(error, `yarn ${command} ${exampleArgs.join(' ')}`)); - } - - yield install(config, reporter, flags, lockfile); - }); - - return function run(_x11, _x12, _x13, _x14) { - return _ref31.apply(this, arguments); - }; -})(); - -let wrapLifecycle = exports.wrapLifecycle = (() => { - var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, flags, factory) { - yield config.executeLifecycleScript('preinstall'); - - yield factory(); - - // npm behaviour, seems kinda funky but yay compatibility - yield config.executeLifecycleScript('install'); - yield config.executeLifecycleScript('postinstall'); - - if (!config.production) { - if (!config.disablePrepublish) { - yield config.executeLifecycleScript('prepublish'); - } - yield config.executeLifecycleScript('prepare'); - } - }); - - return function wrapLifecycle(_x15, _x16, _x17) { - return _ref32.apply(this, arguments); - }; -})(); - -exports.hasWrapper = hasWrapper; -exports.setFlags = setFlags; - -var _objectPath; - -function _load_objectPath() { - return _objectPath = _interopRequireDefault(__webpack_require__(304)); -} - -var _hooks; - -function _load_hooks() { - return _hooks = __webpack_require__(374); -} - -var _index; - -function _load_index() { - return _index = _interopRequireDefault(__webpack_require__(220)); -} - -var _errors; - -function _load_errors() { - return _errors = __webpack_require__(6); -} - -var _integrityChecker; - -function _load_integrityChecker() { - return _integrityChecker = _interopRequireDefault(__webpack_require__(208)); -} - -var _lockfile; - -function _load_lockfile() { - return _lockfile = _interopRequireDefault(__webpack_require__(19)); -} - -var _lockfile2; - -function _load_lockfile2() { - return _lockfile2 = __webpack_require__(19); -} - -var _packageFetcher; - -function _load_packageFetcher() { - return _packageFetcher = _interopRequireWildcard(__webpack_require__(210)); -} - -var _packageInstallScripts; - -function _load_packageInstallScripts() { - return _packageInstallScripts = _interopRequireDefault(__webpack_require__(557)); -} - -var _packageCompatibility; - -function _load_packageCompatibility() { - return _packageCompatibility = _interopRequireWildcard(__webpack_require__(209)); -} - -var _packageResolver; - -function _load_packageResolver() { - return _packageResolver = _interopRequireDefault(__webpack_require__(366)); -} - -var _packageLinker; - -function _load_packageLinker() { - return _packageLinker = _interopRequireDefault(__webpack_require__(211)); -} - -var _index2; - -function _load_index2() { - return _index2 = __webpack_require__(57); -} - -var _index3; - -function _load_index3() { - return _index3 = __webpack_require__(78); -} - -var _autoclean; - -function _load_autoclean() { - return _autoclean = __webpack_require__(354); -} - -var _constants; - -function _load_constants() { - return _constants = _interopRequireWildcard(__webpack_require__(8)); -} - -var _normalizePattern; - -function _load_normalizePattern() { - return _normalizePattern = __webpack_require__(37); -} - -var _fs; - -function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); -} - -var _map; - -function _load_map() { - return _map = _interopRequireDefault(__webpack_require__(29)); -} - -var _yarnVersion; - -function _load_yarnVersion() { - return _yarnVersion = __webpack_require__(120); -} - -var _generatePnpMap; - -function _load_generatePnpMap() { - return _generatePnpMap = __webpack_require__(579); -} - -var _workspaceLayout; - -function _load_workspaceLayout() { - return _workspaceLayout = _interopRequireDefault(__webpack_require__(90)); -} - -var _resolutionMap; - -function _load_resolutionMap() { - return _resolutionMap = _interopRequireDefault(__webpack_require__(214)); -} - -var _guessName; - -function _load_guessName() { - return _guessName = _interopRequireDefault(__webpack_require__(169)); -} - -var _audit; - -function _load_audit() { - return _audit = _interopRequireDefault(__webpack_require__(353)); -} - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const deepEqual = __webpack_require__(631); - -const emoji = __webpack_require__(302); -const invariant = __webpack_require__(9); -const path = __webpack_require__(0); -const semver = __webpack_require__(22); -const uuid = __webpack_require__(119); -const ssri = __webpack_require__(65); - -const ONE_DAY = 1000 * 60 * 60 * 24; - -/** - * Try and detect the installation method for Yarn and provide a command to update it with. - */ - -function getUpdateCommand(installationMethod) { - if (installationMethod === 'tar') { - return `curl --compressed -o- -L ${(_constants || _load_constants()).YARN_INSTALLER_SH} | bash`; - } - - if (installationMethod === 'homebrew') { - return 'brew upgrade yarn'; - } - - if (installationMethod === 'deb') { - return 'sudo apt-get update && sudo apt-get install yarn'; - } - - if (installationMethod === 'rpm') { - return 'sudo yum install yarn'; - } - - if (installationMethod === 'npm') { - return 'npm install --global yarn'; - } - - if (installationMethod === 'chocolatey') { - return 'choco upgrade yarn'; - } - - if (installationMethod === 'apk') { - return 'apk update && apk add -u yarn'; - } - - if (installationMethod === 'portage') { - return 'sudo emerge --sync && sudo emerge -au sys-apps/yarn'; - } - - return null; -} - -function getUpdateInstaller(installationMethod) { - // Windows - if (installationMethod === 'msi') { - return (_constants || _load_constants()).YARN_INSTALLER_MSI; - } - - return null; -} - -function normalizeFlags(config, rawFlags) { - const flags = { - // install - har: !!rawFlags.har, - ignorePlatform: !!rawFlags.ignorePlatform, - ignoreEngines: !!rawFlags.ignoreEngines, - ignoreScripts: !!rawFlags.ignoreScripts, - ignoreOptional: !!rawFlags.ignoreOptional, - force: !!rawFlags.force, - flat: !!rawFlags.flat, - lockfile: rawFlags.lockfile !== false, - pureLockfile: !!rawFlags.pureLockfile, - updateChecksums: !!rawFlags.updateChecksums, - skipIntegrityCheck: !!rawFlags.skipIntegrityCheck, - frozenLockfile: !!rawFlags.frozenLockfile, - linkDuplicates: !!rawFlags.linkDuplicates, - checkFiles: !!rawFlags.checkFiles, - audit: !!rawFlags.audit, - - // add - peer: !!rawFlags.peer, - dev: !!rawFlags.dev, - optional: !!rawFlags.optional, - exact: !!rawFlags.exact, - tilde: !!rawFlags.tilde, - ignoreWorkspaceRootCheck: !!rawFlags.ignoreWorkspaceRootCheck, - - // outdated, update-interactive - includeWorkspaceDeps: !!rawFlags.includeWorkspaceDeps, - - // add, remove, update - workspaceRootIsCwd: rawFlags.workspaceRootIsCwd !== false - }; - - if (config.getOption('ignore-scripts')) { - flags.ignoreScripts = true; - } - - if (config.getOption('ignore-platform')) { - flags.ignorePlatform = true; - } - - if (config.getOption('ignore-engines')) { - flags.ignoreEngines = true; - } - - if (config.getOption('ignore-optional')) { - flags.ignoreOptional = true; - } - - if (config.getOption('force')) { - flags.force = true; - } - - return flags; -} - -class Install { - constructor(flags, config, reporter, lockfile) { - this.rootManifestRegistries = []; - this.rootPatternsToOrigin = (0, (_map || _load_map()).default)(); - this.lockfile = lockfile; - this.reporter = reporter; - this.config = config; - this.flags = normalizeFlags(config, flags); - this.resolutions = (0, (_map || _load_map()).default)(); // Legacy resolutions field used for flat install mode - this.resolutionMap = new (_resolutionMap || _load_resolutionMap()).default(config); // Selective resolutions for nested dependencies - this.resolver = new (_packageResolver || _load_packageResolver()).default(config, lockfile, this.resolutionMap); - this.integrityChecker = new (_integrityChecker || _load_integrityChecker()).default(config); - this.linker = new (_packageLinker || _load_packageLinker()).default(config, this.resolver); - this.scripts = new (_packageInstallScripts || _load_packageInstallScripts()).default(config, this.resolver, this.flags.force); - } - - /** - * Create a list of dependency requests from the current directories manifests. - */ - - fetchRequestFromCwd(excludePatterns = [], ignoreUnusedPatterns = false) { - var _this = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const patterns = []; - const deps = []; - let resolutionDeps = []; - const manifest = {}; - - const ignorePatterns = []; - const usedPatterns = []; - let workspaceLayout; - - // some commands should always run in the context of the entire workspace - const cwd = _this.flags.includeWorkspaceDeps || _this.flags.workspaceRootIsCwd ? _this.config.lockfileFolder : _this.config.cwd; - - // non-workspaces are always root, otherwise check for workspace root - const cwdIsRoot = !_this.config.workspaceRootFolder || _this.config.lockfileFolder === cwd; - - // exclude package names that are in install args - const excludeNames = []; - for (var _iterator = excludePatterns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref; - - if (_isArray) { - if (_i >= _iterator.length) break; - _ref = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref = _i.value; - } - - const pattern = _ref; - - if ((0, (_index3 || _load_index3()).getExoticResolver)(pattern)) { - excludeNames.push((0, (_guessName || _load_guessName()).default)(pattern)); - } else { - // extract the name - const parts = (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern); - excludeNames.push(parts.name); - } - } - - const stripExcluded = function stripExcluded(manifest) { - for (var _iterator2 = excludeNames, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { - var _ref2; - - if (_isArray2) { - if (_i2 >= _iterator2.length) break; - _ref2 = _iterator2[_i2++]; - } else { - _i2 = _iterator2.next(); - if (_i2.done) break; - _ref2 = _i2.value; - } - - const exclude = _ref2; - - if (manifest.dependencies && manifest.dependencies[exclude]) { - delete manifest.dependencies[exclude]; - } - if (manifest.devDependencies && manifest.devDependencies[exclude]) { - delete manifest.devDependencies[exclude]; - } - if (manifest.optionalDependencies && manifest.optionalDependencies[exclude]) { - delete manifest.optionalDependencies[exclude]; - } - } - }; - - for (var _iterator3 = Object.keys((_index2 || _load_index2()).registries), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { - var _ref3; - - if (_isArray3) { - if (_i3 >= _iterator3.length) break; - _ref3 = _iterator3[_i3++]; - } else { - _i3 = _iterator3.next(); - if (_i3.done) break; - _ref3 = _i3.value; - } - - const registry = _ref3; - - const filename = (_index2 || _load_index2()).registries[registry].filename; - - const loc = path.join(cwd, filename); - if (!(yield (_fs || _load_fs()).exists(loc))) { - continue; - } - - _this.rootManifestRegistries.push(registry); - - const projectManifestJson = yield _this.config.readJson(loc); - yield (0, (_index || _load_index()).default)(projectManifestJson, cwd, _this.config, cwdIsRoot); - - Object.assign(_this.resolutions, projectManifestJson.resolutions); - Object.assign(manifest, projectManifestJson); - - _this.resolutionMap.init(_this.resolutions); - for (var _iterator4 = Object.keys(_this.resolutionMap.resolutionsByPackage), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { - var _ref4; - - if (_isArray4) { - if (_i4 >= _iterator4.length) break; - _ref4 = _iterator4[_i4++]; - } else { - _i4 = _iterator4.next(); - if (_i4.done) break; - _ref4 = _i4.value; - } - - const packageName = _ref4; - - const optional = (_objectPath || _load_objectPath()).default.has(manifest.optionalDependencies, packageName) && _this.flags.ignoreOptional; - for (var _iterator8 = _this.resolutionMap.resolutionsByPackage[packageName], _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { - var _ref9; - - if (_isArray8) { - if (_i8 >= _iterator8.length) break; - _ref9 = _iterator8[_i8++]; - } else { - _i8 = _iterator8.next(); - if (_i8.done) break; - _ref9 = _i8.value; - } - - const _ref8 = _ref9; - const pattern = _ref8.pattern; - - resolutionDeps = [...resolutionDeps, { registry, pattern, optional, hint: 'resolution' }]; - } - } - - const pushDeps = function pushDeps(depType, manifest, { hint, optional }, isUsed) { - if (ignoreUnusedPatterns && !isUsed) { - return; - } - // We only take unused dependencies into consideration to get deterministic hoisting. - // Since flat mode doesn't care about hoisting and everything is top level and specified then we can safely - // leave these out. - if (_this.flags.flat && !isUsed) { - return; - } - const depMap = manifest[depType]; - for (const name in depMap) { - if (excludeNames.indexOf(name) >= 0) { - continue; - } - - let pattern = name; - if (!_this.lockfile.getLocked(pattern)) { - // when we use --save we save the dependency to the lockfile with just the name rather than the - // version combo - pattern += '@' + depMap[name]; - } - - // normalization made sure packages are mentioned only once - if (isUsed) { - usedPatterns.push(pattern); - } else { - ignorePatterns.push(pattern); - } - - _this.rootPatternsToOrigin[pattern] = depType; - patterns.push(pattern); - deps.push({ pattern, registry, hint, optional, workspaceName: manifest.name, workspaceLoc: manifest._loc }); - } - }; - - if (cwdIsRoot) { - pushDeps('dependencies', projectManifestJson, { hint: null, optional: false }, true); - pushDeps('devDependencies', projectManifestJson, { hint: 'dev', optional: false }, !_this.config.production); - pushDeps('optionalDependencies', projectManifestJson, { hint: 'optional', optional: true }, true); - } - - if (_this.config.workspaceRootFolder) { - const workspaceLoc = cwdIsRoot ? loc : path.join(_this.config.lockfileFolder, filename); - const workspacesRoot = path.dirname(workspaceLoc); - - let workspaceManifestJson = projectManifestJson; - if (!cwdIsRoot) { - // the manifest we read before was a child workspace, so get the root - workspaceManifestJson = yield _this.config.readJson(workspaceLoc); - yield (0, (_index || _load_index()).default)(workspaceManifestJson, workspacesRoot, _this.config, true); - } - - const workspaces = yield _this.config.resolveWorkspaces(workspacesRoot, workspaceManifestJson); - workspaceLayout = new (_workspaceLayout || _load_workspaceLayout()).default(workspaces, _this.config); - - // add virtual manifest that depends on all workspaces, this way package hoisters and resolvers will work fine - const workspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.dependencies); - for (var _iterator5 = Object.keys(workspaces), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { - var _ref5; - - if (_isArray5) { - if (_i5 >= _iterator5.length) break; - _ref5 = _iterator5[_i5++]; - } else { - _i5 = _iterator5.next(); - if (_i5.done) break; - _ref5 = _i5.value; - } - - const workspaceName = _ref5; - - const workspaceManifest = workspaces[workspaceName].manifest; - workspaceDependencies[workspaceName] = workspaceManifest.version; - - // include dependencies from all workspaces - if (_this.flags.includeWorkspaceDeps) { - pushDeps('dependencies', workspaceManifest, { hint: null, optional: false }, true); - pushDeps('devDependencies', workspaceManifest, { hint: 'dev', optional: false }, !_this.config.production); - pushDeps('optionalDependencies', workspaceManifest, { hint: 'optional', optional: true }, true); - } - } - const virtualDependencyManifest = { - _uid: '', - name: `workspace-aggregator-${uuid.v4()}`, - version: '1.0.0', - _registry: 'npm', - _loc: workspacesRoot, - dependencies: workspaceDependencies, - devDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.devDependencies), - optionalDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.optionalDependencies), - private: workspaceManifestJson.private, - workspaces: workspaceManifestJson.workspaces - }; - workspaceLayout.virtualManifestName = virtualDependencyManifest.name; - const virtualDep = {}; - virtualDep[virtualDependencyManifest.name] = virtualDependencyManifest.version; - workspaces[virtualDependencyManifest.name] = { loc: workspacesRoot, manifest: virtualDependencyManifest }; - - // ensure dependencies that should be excluded are stripped from the correct manifest - stripExcluded(cwdIsRoot ? virtualDependencyManifest : workspaces[projectManifestJson.name].manifest); - - pushDeps('workspaces', { workspaces: virtualDep }, { hint: 'workspaces', optional: false }, true); - - const implicitWorkspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceDependencies); - - for (var _iterator6 = (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { - var _ref6; - - if (_isArray6) { - if (_i6 >= _iterator6.length) break; - _ref6 = _iterator6[_i6++]; - } else { - _i6 = _iterator6.next(); - if (_i6.done) break; - _ref6 = _i6.value; - } - - const type = _ref6; - - for (var _iterator7 = Object.keys(projectManifestJson[type] || {}), _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { - var _ref7; - - if (_isArray7) { - if (_i7 >= _iterator7.length) break; - _ref7 = _iterator7[_i7++]; - } else { - _i7 = _iterator7.next(); - if (_i7.done) break; - _ref7 = _i7.value; - } - - const dependencyName = _ref7; - - delete implicitWorkspaceDependencies[dependencyName]; - } - } - - pushDeps('dependencies', { dependencies: implicitWorkspaceDependencies }, { hint: 'workspaces', optional: false }, true); - } - - break; - } - - // inherit root flat flag - if (manifest.flat) { - _this.flags.flat = true; - } - - return { - requests: [...resolutionDeps, ...deps], - patterns, - manifest, - usedPatterns, - ignorePatterns, - workspaceLayout - }; - })(); - } - - /** - * TODO description - */ - - prepareRequests(requests) { - return requests; - } - - preparePatterns(patterns) { - return patterns; - } - preparePatternsForLinking(patterns, cwdManifest, cwdIsRoot) { - return patterns; - } - - prepareManifests() { - var _this2 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const manifests = yield _this2.config.getRootManifests(); - return manifests; - })(); - } - - bailout(patterns, workspaceLayout) { - var _this3 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - // We don't want to skip the audit - it could yield important errors - if (_this3.flags.audit) { - return false; - } - // PNP is so fast that the integrity check isn't pertinent - if (_this3.config.plugnplayEnabled) { - return false; - } - if (_this3.flags.skipIntegrityCheck || _this3.flags.force) { - return false; - } - const lockfileCache = _this3.lockfile.cache; - if (!lockfileCache) { - return false; - } - const lockfileClean = _this3.lockfile.parseResultType === 'success'; - const match = yield _this3.integrityChecker.check(patterns, lockfileCache, _this3.flags, workspaceLayout); - if (_this3.flags.frozenLockfile && (!lockfileClean || match.missingPatterns.length > 0)) { - throw new (_errors || _load_errors()).MessageError(_this3.reporter.lang('frozenLockfileError')); - } - - const haveLockfile = yield (_fs || _load_fs()).exists(path.join(_this3.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME)); - - const lockfileIntegrityPresent = !_this3.lockfile.hasEntriesExistWithoutIntegrity(); - const integrityBailout = lockfileIntegrityPresent || !_this3.config.autoAddIntegrity; - - if (match.integrityMatches && haveLockfile && lockfileClean && integrityBailout) { - _this3.reporter.success(_this3.reporter.lang('upToDate')); - return true; - } - - if (match.integrityFileMissing && haveLockfile) { - // Integrity file missing, force script installations - _this3.scripts.setForce(true); - return false; - } - - if (match.hardRefreshRequired) { - // e.g. node version doesn't match, force script installations - _this3.scripts.setForce(true); - return false; - } - - if (!patterns.length && !match.integrityFileMissing) { - _this3.reporter.success(_this3.reporter.lang('nothingToInstall')); - yield _this3.createEmptyManifestFolders(); - yield _this3.saveLockfileAndIntegrity(patterns, workspaceLayout); - return true; - } - - return false; - })(); - } - - /** - * Produce empty folders for all used root manifests. - */ - - createEmptyManifestFolders() { - var _this4 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - if (_this4.config.modulesFolder) { - // already created - return; - } - - for (var _iterator9 = _this4.rootManifestRegistries, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { - var _ref10; - - if (_isArray9) { - if (_i9 >= _iterator9.length) break; - _ref10 = _iterator9[_i9++]; - } else { - _i9 = _iterator9.next(); - if (_i9.done) break; - _ref10 = _i9.value; - } - - const registryName = _ref10; - const folder = _this4.config.registries[registryName].folder; - - yield (_fs || _load_fs()).mkdirp(path.join(_this4.config.lockfileFolder, folder)); - } - })(); - } - - /** - * TODO description - */ - - markIgnored(patterns) { - for (var _iterator10 = patterns, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { - var _ref11; - - if (_isArray10) { - if (_i10 >= _iterator10.length) break; - _ref11 = _iterator10[_i10++]; - } else { - _i10 = _iterator10.next(); - if (_i10.done) break; - _ref11 = _i10.value; - } - - const pattern = _ref11; - - const manifest = this.resolver.getStrictResolvedPattern(pattern); - const ref = manifest._reference; - invariant(ref, 'expected package reference'); - - // just mark the package as ignored. if the package is used by a required package, the hoister - // will take care of that. - ref.ignore = true; - } - } - - /** - * helper method that gets only recent manifests - * used by global.ls command - */ - getFlattenedDeps() { - var _this5 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - var _ref12 = yield _this5.fetchRequestFromCwd(); - - const depRequests = _ref12.requests, - rawPatterns = _ref12.patterns; - - - yield _this5.resolver.init(depRequests, {}); - - const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this5.resolver.getManifests(), _this5.config); - _this5.resolver.updateManifests(manifests); - - return _this5.flatten(rawPatterns); - })(); - } - - /** - * TODO description - */ - - init() { - var _this6 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.checkUpdate(); - - // warn if we have a shrinkwrap - if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_SHRINKWRAP_FILENAME))) { - _this6.reporter.warn(_this6.reporter.lang('shrinkwrapWarning')); - } - - // warn if we have an npm lockfile - if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_LOCK_FILENAME))) { - _this6.reporter.warn(_this6.reporter.lang('npmLockfileWarning')); - } - - if (_this6.config.plugnplayEnabled) { - _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L1')); - _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L2')); - } - - let flattenedTopLevelPatterns = []; - const steps = []; - - var _ref13 = yield _this6.fetchRequestFromCwd(); - - const depRequests = _ref13.requests, - rawPatterns = _ref13.patterns, - ignorePatterns = _ref13.ignorePatterns, - workspaceLayout = _ref13.workspaceLayout, - manifest = _ref13.manifest; - - let topLevelPatterns = []; - - const artifacts = yield _this6.integrityChecker.getArtifacts(); - if (artifacts) { - _this6.linker.setArtifacts(artifacts); - _this6.scripts.setArtifacts(artifacts); - } - - if ((_packageCompatibility || _load_packageCompatibility()).shouldCheck(manifest, _this6.flags)) { - steps.push((() => { - var _ref14 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { - _this6.reporter.step(curr, total, _this6.reporter.lang('checkingManifest'), emoji.get('mag')); - yield _this6.checkCompatibility(); - }); - - return function (_x, _x2) { - return _ref14.apply(this, arguments); - }; - })()); - } - - const audit = new (_audit || _load_audit()).default(_this6.config, _this6.reporter, { groups: (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES }); - let auditFoundProblems = false; - - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('resolveStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.reporter.step(curr, total, _this6.reporter.lang('resolvingPackages'), emoji.get('mag')); - yield _this6.resolver.init(_this6.prepareRequests(depRequests), { - isFlat: _this6.flags.flat, - isFrozen: _this6.flags.frozenLockfile, - workspaceLayout - }); - topLevelPatterns = _this6.preparePatterns(rawPatterns); - flattenedTopLevelPatterns = yield _this6.flatten(topLevelPatterns); - return { bailout: !_this6.flags.audit && (yield _this6.bailout(topLevelPatterns, workspaceLayout)) }; - })); - }); - - if (_this6.flags.audit) { - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('auditStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.reporter.step(curr, total, _this6.reporter.lang('auditRunning'), emoji.get('mag')); - if (_this6.flags.offline) { - _this6.reporter.warn(_this6.reporter.lang('auditOffline')); - return { bailout: false }; - } - const preparedManifests = yield _this6.prepareManifests(); - // $FlowFixMe - Flow considers `m` in the map operation to be "mixed", so does not recognize `m.object` - const mergedManifest = Object.assign({}, ...Object.values(preparedManifests).map(function (m) { - return m.object; - })); - const auditVulnerabilityCounts = yield audit.performAudit(mergedManifest, _this6.lockfile, _this6.resolver, _this6.linker, topLevelPatterns); - auditFoundProblems = auditVulnerabilityCounts.info || auditVulnerabilityCounts.low || auditVulnerabilityCounts.moderate || auditVulnerabilityCounts.high || auditVulnerabilityCounts.critical; - return { bailout: yield _this6.bailout(topLevelPatterns, workspaceLayout) }; - })); - }); - } - - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('fetchStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.markIgnored(ignorePatterns); - _this6.reporter.step(curr, total, _this6.reporter.lang('fetchingPackages'), emoji.get('truck')); - const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this6.resolver.getManifests(), _this6.config); - _this6.resolver.updateManifests(manifests); - yield (_packageCompatibility || _load_packageCompatibility()).check(_this6.resolver.getManifests(), _this6.config, _this6.flags.ignoreEngines); - })); - }); - - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('linkStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - // remove integrity hash to make this operation atomic - yield _this6.integrityChecker.removeIntegrityFile(); - _this6.reporter.step(curr, total, _this6.reporter.lang('linkingDependencies'), emoji.get('link')); - flattenedTopLevelPatterns = _this6.preparePatternsForLinking(flattenedTopLevelPatterns, manifest, _this6.config.lockfileFolder === _this6.config.cwd); - yield _this6.linker.init(flattenedTopLevelPatterns, workspaceLayout, { - linkDuplicates: _this6.flags.linkDuplicates, - ignoreOptional: _this6.flags.ignoreOptional - }); - })); - }); - - if (_this6.config.plugnplayEnabled) { - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('pnpStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const pnpPath = `${_this6.config.lockfileFolder}/${(_constants || _load_constants()).PNP_FILENAME}`; - - const code = yield (0, (_generatePnpMap || _load_generatePnpMap()).generatePnpMap)(_this6.config, flattenedTopLevelPatterns, { - resolver: _this6.resolver, - reporter: _this6.reporter, - targetPath: pnpPath, - workspaceLayout - }); - - try { - const file = yield (_fs || _load_fs()).readFile(pnpPath); - if (file === code) { - return; - } - } catch (error) {} - - yield (_fs || _load_fs()).writeFile(pnpPath, code); - yield (_fs || _load_fs()).chmod(pnpPath, 0o755); - })); - }); - } - - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('buildStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.reporter.step(curr, total, _this6.flags.force ? _this6.reporter.lang('rebuildingPackages') : _this6.reporter.lang('buildingFreshPackages'), emoji.get('hammer')); - - if (_this6.config.ignoreScripts) { - _this6.reporter.warn(_this6.reporter.lang('ignoredScripts')); - } else { - yield _this6.scripts.init(flattenedTopLevelPatterns); - } - })); - }); - - if (_this6.flags.har) { - steps.push((() => { - var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { - const formattedDate = new Date().toISOString().replace(/:/g, '-'); - const filename = `yarn-install_${formattedDate}.har`; - _this6.reporter.step(curr, total, _this6.reporter.lang('savingHar', filename), emoji.get('black_circle_for_record')); - yield _this6.config.requestManager.saveHar(filename); - }); - - return function (_x3, _x4) { - return _ref21.apply(this, arguments); - }; - })()); - } - - if (yield _this6.shouldClean()) { - steps.push((() => { - var _ref22 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { - _this6.reporter.step(curr, total, _this6.reporter.lang('cleaningModules'), emoji.get('recycle')); - yield (0, (_autoclean || _load_autoclean()).clean)(_this6.config, _this6.reporter); - }); - - return function (_x5, _x6) { - return _ref22.apply(this, arguments); - }; - })()); - } - - let currentStep = 0; - for (var _iterator11 = steps, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { - var _ref23; - - if (_isArray11) { - if (_i11 >= _iterator11.length) break; - _ref23 = _iterator11[_i11++]; - } else { - _i11 = _iterator11.next(); - if (_i11.done) break; - _ref23 = _i11.value; - } - - const step = _ref23; - - const stepResult = yield step(++currentStep, steps.length); - if (stepResult && stepResult.bailout) { - if (_this6.flags.audit) { - audit.summary(); - } - if (auditFoundProblems) { - _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); - } - _this6.maybeOutputUpdate(); - return flattenedTopLevelPatterns; - } - } - - // fin! - if (_this6.flags.audit) { - audit.summary(); - } - if (auditFoundProblems) { - _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); - } - yield _this6.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); - yield _this6.persistChanges(); - _this6.maybeOutputUpdate(); - _this6.config.requestManager.clearCache(); - return flattenedTopLevelPatterns; - })(); - } - - checkCompatibility() { - var _this7 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - var _ref24 = yield _this7.fetchRequestFromCwd(); - - const manifest = _ref24.manifest; - - yield (_packageCompatibility || _load_packageCompatibility()).checkOne(manifest, _this7.config, _this7.flags.ignoreEngines); - })(); - } - - persistChanges() { - var _this8 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - // get all the different registry manifests in this folder - const manifests = yield _this8.config.getRootManifests(); - - if (yield _this8.applyChanges(manifests)) { - yield _this8.config.saveRootManifests(manifests); - } - })(); - } - - applyChanges(manifests) { - let hasChanged = false; - - if (this.config.plugnplayPersist) { - const object = manifests.npm.object; - - - if (typeof object.installConfig !== 'object') { - object.installConfig = {}; - } - - if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) { - object.installConfig.pnp = true; - hasChanged = true; - } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') { - delete object.installConfig.pnp; - hasChanged = true; - } - - if (Object.keys(object.installConfig).length === 0) { - delete object.installConfig; - } - } - - return Promise.resolve(hasChanged); - } - - /** - * Check if we should run the cleaning step. - */ - - shouldClean() { - return (_fs || _load_fs()).exists(path.join(this.config.lockfileFolder, (_constants || _load_constants()).CLEAN_FILENAME)); - } - - /** - * TODO - */ - - flatten(patterns) { - var _this9 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - if (!_this9.flags.flat) { - return patterns; - } - - const flattenedPatterns = []; - - for (var _iterator12 = _this9.resolver.getAllDependencyNamesByLevelOrder(patterns), _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { - var _ref25; - - if (_isArray12) { - if (_i12 >= _iterator12.length) break; - _ref25 = _iterator12[_i12++]; - } else { - _i12 = _iterator12.next(); - if (_i12.done) break; - _ref25 = _i12.value; - } - - const name = _ref25; - - const infos = _this9.resolver.getAllInfoForPackageName(name).filter(function (manifest) { - const ref = manifest._reference; - invariant(ref, 'expected package reference'); - return !ref.ignore; - }); - - if (infos.length === 0) { - continue; - } - - if (infos.length === 1) { - // single version of this package - // take out a single pattern as multiple patterns may have resolved to this package - flattenedPatterns.push(_this9.resolver.patternsByPackage[name][0]); - continue; - } - - const options = infos.map(function (info) { - const ref = info._reference; - invariant(ref, 'expected reference'); - return { - // TODO `and is required by {PARENT}`, - name: _this9.reporter.lang('manualVersionResolutionOption', ref.patterns.join(', '), info.version), - - value: info.version - }; - }); - const versions = infos.map(function (info) { - return info.version; - }); - let version; - - const resolutionVersion = _this9.resolutions[name]; - if (resolutionVersion && versions.indexOf(resolutionVersion) >= 0) { - // use json `resolution` version - version = resolutionVersion; - } else { - version = yield _this9.reporter.select(_this9.reporter.lang('manualVersionResolution', name), _this9.reporter.lang('answer'), options); - _this9.resolutions[name] = version; - } - - flattenedPatterns.push(_this9.resolver.collapseAllVersionsOfPackage(name, version)); - } - - // save resolutions to their appropriate root manifest - if (Object.keys(_this9.resolutions).length) { - const manifests = yield _this9.config.getRootManifests(); - - for (const name in _this9.resolutions) { - const version = _this9.resolutions[name]; - - const patterns = _this9.resolver.patternsByPackage[name]; - if (!patterns) { - continue; - } - - let manifest; - for (var _iterator13 = patterns, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { - var _ref26; - - if (_isArray13) { - if (_i13 >= _iterator13.length) break; - _ref26 = _iterator13[_i13++]; - } else { - _i13 = _iterator13.next(); - if (_i13.done) break; - _ref26 = _i13.value; - } - - const pattern = _ref26; - - manifest = _this9.resolver.getResolvedPattern(pattern); - if (manifest) { - break; - } - } - invariant(manifest, 'expected manifest'); - - const ref = manifest._reference; - invariant(ref, 'expected reference'); - - const object = manifests[ref.registry].object; - object.resolutions = object.resolutions || {}; - object.resolutions[name] = version; - } - - yield _this9.config.saveRootManifests(manifests); - } - - return flattenedPatterns; - })(); - } - - /** - * Remove offline tarballs that are no longer required - */ - - pruneOfflineMirror(lockfile) { - var _this10 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const mirror = _this10.config.getOfflineMirrorPath(); - if (!mirror) { - return; - } - - const requiredTarballs = new Set(); - for (const dependency in lockfile) { - const resolved = lockfile[dependency].resolved; - if (resolved) { - const basename = path.basename(resolved.split('#')[0]); - if (dependency[0] === '@' && basename[0] !== '@') { - requiredTarballs.add(`${dependency.split('/')[0]}-${basename}`); - } - requiredTarballs.add(basename); - } - } - - const mirrorFiles = yield (_fs || _load_fs()).walk(mirror); - for (var _iterator14 = mirrorFiles, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { - var _ref27; - - if (_isArray14) { - if (_i14 >= _iterator14.length) break; - _ref27 = _iterator14[_i14++]; - } else { - _i14 = _iterator14.next(); - if (_i14.done) break; - _ref27 = _i14.value; - } - - const file = _ref27; - - const isTarball = path.extname(file.basename) === '.tgz'; - // if using experimental-pack-script-packages-in-mirror flag, don't unlink prebuilt2 packages - const hasprebuilt2Package = file.relative.startsWith('prebuilt2/'); - if (isTarball && !hasprebuilt2Package && !requiredTarballs.has(file.basename)) { - yield (_fs || _load_fs()).unlink(file.absolute); - } - } - })(); - } - - /** - * Save updated integrity and lockfiles. - */ - - saveLockfileAndIntegrity(patterns, workspaceLayout) { - var _this11 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const resolvedPatterns = {}; - Object.keys(_this11.resolver.patterns).forEach(function (pattern) { - if (!workspaceLayout || !workspaceLayout.getManifestByPattern(pattern)) { - resolvedPatterns[pattern] = _this11.resolver.patterns[pattern]; - } - }); - - // TODO this code is duplicated in a few places, need a common way to filter out workspace patterns from lockfile - patterns = patterns.filter(function (p) { - return !workspaceLayout || !workspaceLayout.getManifestByPattern(p); - }); - - const lockfileBasedOnResolver = _this11.lockfile.getLockfile(resolvedPatterns); - - if (_this11.config.pruneOfflineMirror) { - yield _this11.pruneOfflineMirror(lockfileBasedOnResolver); - } - - // write integrity hash - if (!_this11.config.plugnplayEnabled) { - yield _this11.integrityChecker.save(patterns, lockfileBasedOnResolver, _this11.flags, workspaceLayout, _this11.scripts.getArtifacts()); - } - - // --no-lockfile or --pure-lockfile or --frozen-lockfile - if (_this11.flags.lockfile === false || _this11.flags.pureLockfile || _this11.flags.frozenLockfile) { - return; - } - - const lockFileHasAllPatterns = patterns.every(function (p) { - return _this11.lockfile.getLocked(p); - }); - const lockfilePatternsMatch = Object.keys(_this11.lockfile.cache || {}).every(function (p) { - return lockfileBasedOnResolver[p]; - }); - const resolverPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { - const manifest = _this11.lockfile.getLocked(pattern); - return manifest && manifest.resolved === lockfileBasedOnResolver[pattern].resolved && deepEqual(manifest.prebuilt2Variants, lockfileBasedOnResolver[pattern].prebuilt2Variants); - }); - const integrityPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { - const existingIntegrityInfo = lockfileBasedOnResolver[pattern].integrity; - if (!existingIntegrityInfo) { - // if this entry does not have an integrity, no need to re-write the lockfile because of it - return true; - } - const manifest = _this11.lockfile.getLocked(pattern); - if (manifest && manifest.integrity) { - const manifestIntegrity = ssri.stringify(manifest.integrity); - return manifestIntegrity === existingIntegrityInfo; - } - return false; - }); - - // remove command is followed by install with force, lockfile will be rewritten in any case then - if (!_this11.flags.force && _this11.lockfile.parseResultType === 'success' && lockFileHasAllPatterns && lockfilePatternsMatch && resolverPatternsAreSameAsInLockfile && integrityPatternsAreSameAsInLockfile && patterns.length) { - return; - } - - // build lockfile location - const loc = path.join(_this11.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME); - - // write lockfile - const lockSource = (0, (_lockfile2 || _load_lockfile2()).stringify)(lockfileBasedOnResolver, false, _this11.config.enableLockfileVersions); - yield (_fs || _load_fs()).writeFilePreservingEol(loc, lockSource); - - _this11._logSuccessSaveLockfile(); - })(); - } - - _logSuccessSaveLockfile() { - this.reporter.success(this.reporter.lang('savedLockfile')); - } - - /** - * Load the dependency graph of the current install. Only does package resolving and wont write to the cwd. - */ - hydrate(ignoreUnusedPatterns) { - var _this12 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const request = yield _this12.fetchRequestFromCwd([], ignoreUnusedPatterns); - const depRequests = request.requests, - rawPatterns = request.patterns, - ignorePatterns = request.ignorePatterns, - workspaceLayout = request.workspaceLayout; - - - yield _this12.resolver.init(depRequests, { - isFlat: _this12.flags.flat, - isFrozen: _this12.flags.frozenLockfile, - workspaceLayout - }); - yield _this12.flatten(rawPatterns); - _this12.markIgnored(ignorePatterns); - - // fetch packages, should hit cache most of the time - const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this12.resolver.getManifests(), _this12.config); - _this12.resolver.updateManifests(manifests); - yield (_packageCompatibility || _load_packageCompatibility()).check(_this12.resolver.getManifests(), _this12.config, _this12.flags.ignoreEngines); - - // expand minimal manifests - for (var _iterator15 = _this12.resolver.getManifests(), _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { - var _ref28; - - if (_isArray15) { - if (_i15 >= _iterator15.length) break; - _ref28 = _iterator15[_i15++]; - } else { - _i15 = _iterator15.next(); - if (_i15.done) break; - _ref28 = _i15.value; - } - - const manifest = _ref28; - - const ref = manifest._reference; - invariant(ref, 'expected reference'); - const type = ref.remote.type; - // link specifier won't ever hit cache - - let loc = ''; - if (type === 'link') { - continue; - } else if (type === 'workspace') { - if (!ref.remote.reference) { - continue; - } - loc = ref.remote.reference; - } else { - loc = _this12.config.generateModuleCachePath(ref); - } - const newPkg = yield _this12.config.readManifest(loc); - yield _this12.resolver.updateManifest(ref, newPkg); - } - - return request; - })(); - } - - /** - * Check for updates every day and output a nag message if there's a newer version. - */ - - checkUpdate() { - if (this.config.nonInteractive) { - // don't show upgrade dialog on CI or non-TTY terminals - return; - } - - // don't check if disabled - if (this.config.getOption('disable-self-update-check')) { - return; - } - - // only check for updates once a day - const lastUpdateCheck = Number(this.config.getOption('lastUpdateCheck')) || 0; - if (lastUpdateCheck && Date.now() - lastUpdateCheck < ONE_DAY) { - return; - } - - // don't bug for updates on tagged releases - if ((_yarnVersion || _load_yarnVersion()).version.indexOf('-') >= 0) { - return; - } - - this._checkUpdate().catch(() => { - // swallow errors - }); - } - - _checkUpdate() { - var _this13 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - let latestVersion = yield _this13.config.requestManager.request({ - url: (_constants || _load_constants()).SELF_UPDATE_VERSION_URL - }); - invariant(typeof latestVersion === 'string', 'expected string'); - latestVersion = latestVersion.trim(); - if (!semver.valid(latestVersion)) { - return; - } - - // ensure we only check for updates periodically - _this13.config.registries.yarn.saveHomeConfig({ - lastUpdateCheck: Date.now() - }); - - if (semver.gt(latestVersion, (_yarnVersion || _load_yarnVersion()).version)) { - const installationMethod = yield (0, (_yarnVersion || _load_yarnVersion()).getInstallationMethod)(); - _this13.maybeOutputUpdate = function () { - _this13.reporter.warn(_this13.reporter.lang('yarnOutdated', latestVersion, (_yarnVersion || _load_yarnVersion()).version)); - - const command = getUpdateCommand(installationMethod); - if (command) { - _this13.reporter.info(_this13.reporter.lang('yarnOutdatedCommand')); - _this13.reporter.command(command); - } else { - const installer = getUpdateInstaller(installationMethod); - if (installer) { - _this13.reporter.info(_this13.reporter.lang('yarnOutdatedInstaller', installer)); - } - } - }; - } - })(); - } - - /** - * Method to override with a possible upgrade message. - */ - - maybeOutputUpdate() {} -} - -exports.Install = Install; -function hasWrapper(commander, args) { - return true; -} - -function setFlags(commander) { - commander.description('Yarn install is used to install all dependencies for a project.'); - commander.usage('install [flags]'); - commander.option('-A, --audit', 'Run vulnerability audit on installed packages'); - commander.option('-g, --global', 'DEPRECATED'); - commander.option('-S, --save', 'DEPRECATED - save package to your `dependencies`'); - commander.option('-D, --save-dev', 'DEPRECATED - save package to your `devDependencies`'); - commander.option('-P, --save-peer', 'DEPRECATED - save package to your `peerDependencies`'); - commander.option('-O, --save-optional', 'DEPRECATED - save package to your `optionalDependencies`'); - commander.option('-E, --save-exact', 'DEPRECATED'); - commander.option('-T, --save-tilde', 'DEPRECATED'); -} - -/***/ }), -/* 35 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(52); -module.exports = function (it) { - if (!isObject(it)) throw TypeError(it + ' is not an object!'); - return it; -}; - - -/***/ }), -/* 36 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return SubjectSubscriber; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subject; }); -/* unused harmony export AnonymousSubject */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Observable__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Subscriber__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__ = __webpack_require__(189); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__ = __webpack_require__(422); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__ = __webpack_require__(321); -/** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */ - - - - - - - -var SubjectSubscriber = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SubjectSubscriber, _super); - function SubjectSubscriber(destination) { - var _this = _super.call(this, destination) || this; - _this.destination = destination; - return _this; - } - return SubjectSubscriber; -}(__WEBPACK_IMPORTED_MODULE_2__Subscriber__["a" /* Subscriber */])); - -var Subject = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subject, _super); - function Subject() { - var _this = _super.call(this) || this; - _this.observers = []; - _this.closed = false; - _this.isStopped = false; - _this.hasError = false; - _this.thrownError = null; - return _this; - } - Subject.prototype[__WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { - return new SubjectSubscriber(this); - }; - Subject.prototype.lift = function (operator) { - var subject = new AnonymousSubject(this, this); - subject.operator = operator; - return subject; - }; - Subject.prototype.next = function (value) { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - if (!this.isStopped) { - var observers = this.observers; - var len = observers.length; - var copy = observers.slice(); - for (var i = 0; i < len; i++) { - copy[i].next(value); - } - } - }; - Subject.prototype.error = function (err) { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - this.hasError = true; - this.thrownError = err; - this.isStopped = true; - var observers = this.observers; - var len = observers.length; - var copy = observers.slice(); - for (var i = 0; i < len; i++) { - copy[i].error(err); - } - this.observers.length = 0; - }; - Subject.prototype.complete = function () { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - this.isStopped = true; - var observers = this.observers; - var len = observers.length; - var copy = observers.slice(); - for (var i = 0; i < len; i++) { - copy[i].complete(); - } - this.observers.length = 0; - }; - Subject.prototype.unsubscribe = function () { - this.isStopped = true; - this.closed = true; - this.observers = null; - }; - Subject.prototype._trySubscribe = function (subscriber) { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - else { - return _super.prototype._trySubscribe.call(this, subscriber); - } - }; - Subject.prototype._subscribe = function (subscriber) { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - else if (this.hasError) { - subscriber.error(this.thrownError); - return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; - } - else if (this.isStopped) { - subscriber.complete(); - return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; - } - else { - this.observers.push(subscriber); - return new __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__["a" /* SubjectSubscription */](this, subscriber); - } - }; - Subject.prototype.asObservable = function () { - var observable = new __WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */](); - observable.source = this; - return observable; - }; - Subject.create = function (destination, source) { - return new AnonymousSubject(destination, source); - }; - return Subject; -}(__WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */])); - -var AnonymousSubject = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](AnonymousSubject, _super); - function AnonymousSubject(destination, source) { - var _this = _super.call(this) || this; - _this.destination = destination; - _this.source = source; - return _this; - } - AnonymousSubject.prototype.next = function (value) { - var destination = this.destination; - if (destination && destination.next) { - destination.next(value); - } - }; - AnonymousSubject.prototype.error = function (err) { - var destination = this.destination; - if (destination && destination.error) { - this.destination.error(err); - } - }; - AnonymousSubject.prototype.complete = function () { - var destination = this.destination; - if (destination && destination.complete) { - this.destination.complete(); - } - }; - AnonymousSubject.prototype._subscribe = function (subscriber) { - var source = this.source; - if (source) { - return this.source.subscribe(subscriber); - } - else { - return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; - } - }; - return AnonymousSubject; -}(Subject)); - -//# sourceMappingURL=Subject.js.map - - -/***/ }), -/* 37 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.normalizePattern = normalizePattern; - -/** - * Explode and normalize a pattern into its name and range. - */ - -function normalizePattern(pattern) { - let hasVersion = false; - let range = 'latest'; - let name = pattern; - - // if we're a scope then remove the @ and add it back later - let isScoped = false; - if (name[0] === '@') { - isScoped = true; - name = name.slice(1); - } - - // take first part as the name - const parts = name.split('@'); - if (parts.length > 1) { - name = parts.shift(); - range = parts.join('@'); - - if (range) { - hasVersion = true; - } else { - range = '*'; - } - } - - // add back @ scope suffix - if (isScoped) { - name = `@${name}`; - } - - return { name, range, hasVersion }; -} - -/***/ }), -/* 38 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {var __WEBPACK_AMD_DEFINE_RESULT__;/** - * @license - * Lodash - * Copyright JS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -;(function() { - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the semantic version number. */ - var VERSION = '4.17.10'; - - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Error message constants. */ - var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', - FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED = '__lodash_hash_undefined__'; - - /** Used as the maximum memoize cache size. */ - var MAX_MEMOIZE_SIZE = 500; - - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - - /** Used to compose bitmasks for cloning. */ - var CLONE_DEEP_FLAG = 1, - CLONE_FLAT_FLAG = 2, - CLONE_SYMBOLS_FLAG = 4; - - /** Used to compose bitmasks for value comparisons. */ - var COMPARE_PARTIAL_FLAG = 1, - COMPARE_UNORDERED_FLAG = 2; - - /** Used to compose bitmasks for function metadata. */ - var WRAP_BIND_FLAG = 1, - WRAP_BIND_KEY_FLAG = 2, - WRAP_CURRY_BOUND_FLAG = 4, - WRAP_CURRY_FLAG = 8, - WRAP_CURRY_RIGHT_FLAG = 16, - WRAP_PARTIAL_FLAG = 32, - WRAP_PARTIAL_RIGHT_FLAG = 64, - WRAP_ARY_FLAG = 128, - WRAP_REARG_FLAG = 256, - WRAP_FLIP_FLAG = 512; - - /** Used as default options for `_.truncate`. */ - var DEFAULT_TRUNC_LENGTH = 30, - DEFAULT_TRUNC_OMISSION = '...'; - - /** Used to detect hot functions by number of calls within a span of milliseconds. */ - var HOT_COUNT = 800, - HOT_SPAN = 16; - - /** Used to indicate the type of lazy iteratees. */ - var LAZY_FILTER_FLAG = 1, - LAZY_MAP_FLAG = 2, - LAZY_WHILE_FLAG = 3; - - /** Used as references for various `Number` constants. */ - var INFINITY = 1 / 0, - MAX_SAFE_INTEGER = 9007199254740991, - MAX_INTEGER = 1.7976931348623157e+308, - NAN = 0 / 0; - - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, - HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - - /** Used to associate wrap methods with their bit flags. */ - var wrapFlags = [ - ['ary', WRAP_ARY_FLAG], - ['bind', WRAP_BIND_FLAG], - ['bindKey', WRAP_BIND_KEY_FLAG], - ['curry', WRAP_CURRY_FLAG], - ['curryRight', WRAP_CURRY_RIGHT_FLAG], - ['flip', WRAP_FLIP_FLAG], - ['partial', WRAP_PARTIAL_FLAG], - ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], - ['rearg', WRAP_REARG_FLAG] - ]; - - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - asyncTag = '[object AsyncFunction]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - domExcTag = '[object DOMException]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - mapTag = '[object Map]', - numberTag = '[object Number]', - nullTag = '[object Null]', - objectTag = '[object Object]', - promiseTag = '[object Promise]', - proxyTag = '[object Proxy]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - symbolTag = '[object Symbol]', - undefinedTag = '[object Undefined]', - weakMapTag = '[object WeakMap]', - weakSetTag = '[object WeakSet]'; - - var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - - /** Used to match empty string literals in compiled template source. */ - var reEmptyStringLeading = /\b__p \+= '';/g, - reEmptyStringMiddle = /\b(__p \+=) '' \+/g, - reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - - /** Used to match HTML entities and HTML characters. */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, - reUnescapedHtml = /[&<>"']/g, - reHasEscapedHtml = RegExp(reEscapedHtml.source), - reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - - /** Used to match template delimiters. */ - var reEscape = /<%-([\s\S]+?)%>/g, - reEvaluate = /<%([\s\S]+?)%>/g, - reInterpolate = /<%=([\s\S]+?)%>/g; - - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - - /** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, - reHasRegExpChar = RegExp(reRegExpChar.source); - - /** Used to match leading and trailing whitespace. */ - var reTrim = /^\s+|\s+$/g, - reTrimStart = /^\s+/, - reTrimEnd = /\s+$/; - - /** Used to match wrap detail comments. */ - var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, - reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, - reSplitDetails = /,? & /; - - /** Used to match words composed of alphanumeric characters. */ - var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; - - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; - - /** - * Used to match - * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). - */ - var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - - /** Used to match `RegExp` flags from their coerced string values. */ - var reFlags = /\w*$/; - - /** Used to detect bad signed hexadecimal string values. */ - var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - - /** Used to detect binary string values. */ - var reIsBinary = /^0b[01]+$/i; - - /** Used to detect host constructors (Safari). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - /** Used to detect octal string values. */ - var reIsOctal = /^0o[0-7]+$/i; - - /** Used to detect unsigned integer values. */ - var reIsUint = /^(?:0|[1-9]\d*)$/; - - /** Used to match Latin Unicode letters (excluding mathematical operators). */ - var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; - - /** Used to ensure capturing order of template delimiters. */ - var reNoMatch = /($^)/; - - /** Used to match unescaped characters in compiled string literals. */ - var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - - /** Used to compose unicode character classes. */ - var rsAstralRange = '\\ud800-\\udfff', - rsComboMarksRange = '\\u0300-\\u036f', - reComboHalfMarksRange = '\\ufe20-\\ufe2f', - rsComboSymbolsRange = '\\u20d0-\\u20ff', - rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, - rsDingbatRange = '\\u2700-\\u27bf', - rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', - rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', - rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', - rsPunctuationRange = '\\u2000-\\u206f', - rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', - rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', - rsVarRange = '\\ufe0e\\ufe0f', - rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; - - /** Used to compose unicode capture groups. */ - var rsApos = "['\u2019]", - rsAstral = '[' + rsAstralRange + ']', - rsBreak = '[' + rsBreakRange + ']', - rsCombo = '[' + rsComboRange + ']', - rsDigits = '\\d+', - rsDingbat = '[' + rsDingbatRange + ']', - rsLower = '[' + rsLowerRange + ']', - rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', - rsFitz = '\\ud83c[\\udffb-\\udfff]', - rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', - rsNonAstral = '[^' + rsAstralRange + ']', - rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', - rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', - rsUpper = '[' + rsUpperRange + ']', - rsZWJ = '\\u200d'; - - /** Used to compose unicode regexes. */ - var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', - rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', - rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', - rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', - reOptMod = rsModifier + '?', - rsOptVar = '[' + rsVarRange + ']?', - rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', - rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])', - rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])', - rsSeq = rsOptVar + reOptMod + rsOptJoin, - rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, - rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; - - /** Used to match apostrophes. */ - var reApos = RegExp(rsApos, 'g'); - - /** - * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and - * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). - */ - var reComboMark = RegExp(rsCombo, 'g'); - - /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ - var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); - - /** Used to match complex or compound words. */ - var reUnicodeWord = RegExp([ - rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', - rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', - rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, - rsUpper + '+' + rsOptContrUpper, - rsOrdUpper, - rsOrdLower, - rsDigits, - rsEmoji - ].join('|'), 'g'); - - /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ - var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); - - /** Used to detect strings that need a more robust regexp to match words. */ - var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; - - /** Used to assign default `context` object properties. */ - var contextProps = [ - 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', - 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', - 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', - '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' - ]; - - /** Used to make template sourceURLs easier to identify. */ - var templateCounter = -1; - - /** Used to identify `toStringTag` values of typed arrays. */ - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = - typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = - typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = - typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = - typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = - typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = - typedArrayTags[errorTag] = typedArrayTags[funcTag] = - typedArrayTags[mapTag] = typedArrayTags[numberTag] = - typedArrayTags[objectTag] = typedArrayTags[regexpTag] = - typedArrayTags[setTag] = typedArrayTags[stringTag] = - typedArrayTags[weakMapTag] = false; - - /** Used to identify `toStringTag` values supported by `_.clone`. */ - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = - cloneableTags[boolTag] = cloneableTags[dateTag] = - cloneableTags[float32Tag] = cloneableTags[float64Tag] = - cloneableTags[int8Tag] = cloneableTags[int16Tag] = - cloneableTags[int32Tag] = cloneableTags[mapTag] = - cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[setTag] = - cloneableTags[stringTag] = cloneableTags[symbolTag] = - cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = - cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = - cloneableTags[weakMapTag] = false; - - /** Used to map Latin Unicode letters to basic Latin letters. */ - var deburredLetters = { - // Latin-1 Supplement block. - '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', - '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', - '\xc7': 'C', '\xe7': 'c', - '\xd0': 'D', '\xf0': 'd', - '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', - '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', - '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', - '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', - '\xd1': 'N', '\xf1': 'n', - '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', - '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', - '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', - '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', - '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', - '\xc6': 'Ae', '\xe6': 'ae', - '\xde': 'Th', '\xfe': 'th', - '\xdf': 'ss', - // Latin Extended-A block. - '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', - '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', - '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', - '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', - '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', - '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', - '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', - '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', - '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', - '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', - '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', - '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', - '\u0134': 'J', '\u0135': 'j', - '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', - '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', - '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', - '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', - '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', - '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', - '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', - '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', - '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', - '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', - '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', - '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', - '\u0163': 't', '\u0165': 't', '\u0167': 't', - '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', - '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', - '\u0174': 'W', '\u0175': 'w', - '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', - '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', - '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', - '\u0132': 'IJ', '\u0133': 'ij', - '\u0152': 'Oe', '\u0153': 'oe', - '\u0149': "'n", '\u017f': 's' - }; - - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''' - }; - - /** Used to map HTML entities to characters. */ - var htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'" - }; - - /** Used to escape characters for inclusion in compiled string literals. */ - var stringEscapes = { - '\\': '\\', - "'": "'", - '\n': 'n', - '\r': 'r', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - /** Built-in method references without a dependency on `root`. */ - var freeParseFloat = parseFloat, - freeParseInt = parseInt; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - - /** Detect free variable `self`. */ - var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - - /** Used as a reference to the global object. */ - var root = freeGlobal || freeSelf || Function('return this')(); - - /** Detect free variable `exports`. */ - var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports; - - /** Detect free variable `process` from Node.js. */ - var freeProcess = moduleExports && freeGlobal.process; - - /** Used to access faster Node.js helpers. */ - var nodeUtil = (function() { - try { - // Use `util.types` for Node.js 10+. - var types = freeModule && freeModule.require && freeModule.require('util').types; - - if (types) { - return types; - } - - // Legacy `process.binding('util')` for Node.js < 10. - return freeProcess && freeProcess.binding && freeProcess.binding('util'); - } catch (e) {} - }()); - - /* Node.js helper references. */ - var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, - nodeIsDate = nodeUtil && nodeUtil.isDate, - nodeIsMap = nodeUtil && nodeUtil.isMap, - nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, - nodeIsSet = nodeUtil && nodeUtil.isSet, - nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; - - /*--------------------------------------------------------------------------*/ - - /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} args The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ - function apply(func, thisArg, args) { - switch (args.length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); - } - - /** - * A specialized version of `baseAggregator` for arrays. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform keys. - * @param {Object} accumulator The initial aggregated object. - * @returns {Function} Returns `accumulator`. - */ - function arrayAggregator(array, setter, iteratee, accumulator) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - var value = array[index]; - setter(accumulator, value, iteratee(value), array); - } - return accumulator; - } - - /** - * A specialized version of `_.forEach` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEach(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.forEachRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEachRight(array, iteratee) { - var length = array == null ? 0 : array.length; - - while (length--) { - if (iteratee(array[length], length, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.every` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - */ - function arrayEvery(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } - } - return true; - } - - /** - * A specialized version of `_.filter` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function arrayFilter(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * A specialized version of `_.includes` for arrays without support for - * specifying an index to search from. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludes(array, value) { - var length = array == null ? 0 : array.length; - return !!length && baseIndexOf(array, value, 0) > -1; - } - - /** - * This function is like `arrayIncludes` except that it accepts a comparator. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @param {Function} comparator The comparator invoked per element. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludesWith(array, value, comparator) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (comparator(value, array[index])) { - return true; - } - } - return false; - } - - /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function arrayMap(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } - - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; - - while (++index < length) { - array[offset + index] = values[index]; - } - return array; - } - - /** - * A specialized version of `_.reduce` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initAccum] Specify using the first element of `array` as - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initAccum) { - var index = -1, - length = array == null ? 0 : array.length; - - if (initAccum && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } - - /** - * A specialized version of `_.reduceRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initAccum] Specify using the last element of `array` as - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduceRight(array, iteratee, accumulator, initAccum) { - var length = array == null ? 0 : array.length; - if (initAccum && length) { - accumulator = array[--length]; - } - while (length--) { - accumulator = iteratee(accumulator, array[length], length, array); - } - return accumulator; - } - - /** - * A specialized version of `_.some` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function arraySome(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; - } - - /** - * Gets the size of an ASCII `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - var asciiSize = baseProperty('length'); - - /** - * Converts an ASCII `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function asciiToArray(string) { - return string.split(''); - } - - /** - * Splits an ASCII `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function asciiWords(string) { - return string.match(reAsciiWord) || []; - } - - /** - * The base implementation of methods like `_.findKey` and `_.findLastKey`, - * without support for iteratee shorthands, which iterates over `collection` - * using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFindKey(collection, predicate, eachFunc) { - var result; - eachFunc(collection, function(value, key, collection) { - if (predicate(value, key, collection)) { - result = key; - return false; - } - }); - return result; - } - - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {number} fromIndex The index to search from. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseFindIndex(array, predicate, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); - - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - return value === value - ? strictIndexOf(array, value, fromIndex) - : baseFindIndex(array, baseIsNaN, fromIndex); - } - - /** - * This function is like `baseIndexOf` except that it accepts a comparator. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @param {Function} comparator The comparator invoked per element. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOfWith(array, value, fromIndex, comparator) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (comparator(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.isNaN` without support for number objects. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - */ - function baseIsNaN(value) { - return value !== value; - } - - /** - * The base implementation of `_.mean` and `_.meanBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the mean. - */ - function baseMean(array, iteratee) { - var length = array == null ? 0 : array.length; - return length ? (baseSum(array, iteratee) / length) : NAN; - } - - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } - - /** - * The base implementation of `_.propertyOf` without support for deep paths. - * - * @private - * @param {Object} object The object to query. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyOf(object) { - return function(key) { - return object == null ? undefined : object[key]; - }; - } - - /** - * The base implementation of `_.reduce` and `_.reduceRight`, without support - * for iteratee shorthands, which iterates over `collection` using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initAccum Specify using the first or last element of - * `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initAccum - ? (initAccum = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.sortBy` which uses `comparer` to define the - * sort order of `array` and replaces criteria objects with their corresponding - * values. - * - * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. - */ - function baseSortBy(array, comparer) { - var length = array.length; - - array.sort(comparer); - while (length--) { - array[length] = array[length].value; - } - return array; - } - - /** - * The base implementation of `_.sum` and `_.sumBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(array, iteratee) { - var result, - index = -1, - length = array.length; - - while (++index < length) { - var current = iteratee(array[index]); - if (current !== undefined) { - result = result === undefined ? current : (result + current); - } - } - return result; - } - - /** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ - function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); - - while (++index < n) { - result[index] = iteratee(index); - } - return result; - } - - /** - * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array - * of key-value pairs for `object` corresponding to the property names of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the key-value pairs. - */ - function baseToPairs(object, props) { - return arrayMap(props, function(key) { - return [key, object[key]]; - }); - } - - /** - * The base implementation of `_.unary` without support for storing metadata. - * - * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - */ - function baseUnary(func) { - return function(value) { - return func(value); - }; - } - - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - return arrayMap(props, function(key) { - return object[key]; - }); - } - - /** - * Checks if a `cache` value for `key` exists. - * - * @private - * @param {Object} cache The cache to query. - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function cacheHas(cache, key) { - return cache.has(key); - } - - /** - * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the first unmatched string symbol. - */ - function charsStartIndex(strSymbols, chrSymbols) { - var index = -1, - length = strSymbols.length; - - while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the last unmatched string symbol. - */ - function charsEndIndex(strSymbols, chrSymbols) { - var index = strSymbols.length; - - while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Gets the number of `placeholder` occurrences in `array`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} placeholder The placeholder to search for. - * @returns {number} Returns the placeholder count. - */ - function countHolders(array, placeholder) { - var length = array.length, - result = 0; - - while (length--) { - if (array[length] === placeholder) { - ++result; - } - } - return result; - } - - /** - * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A - * letters to basic Latin letters. - * - * @private - * @param {string} letter The matched letter to deburr. - * @returns {string} Returns the deburred letter. - */ - var deburrLetter = basePropertyOf(deburredLetters); - - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - var escapeHtmlChar = basePropertyOf(htmlEscapes); - - /** - * Used by `_.template` to escape characters for inclusion in compiled string literals. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeStringChar(chr) { - return '\\' + stringEscapes[chr]; - } - - /** - * Gets the value at `key` of `object`. - * - * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ - function getValue(object, key) { - return object == null ? undefined : object[key]; - } - - /** - * Checks if `string` contains Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a symbol is found, else `false`. - */ - function hasUnicode(string) { - return reHasUnicode.test(string); - } - - /** - * Checks if `string` contains a word composed of Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a word is found, else `false`. - */ - function hasUnicodeWord(string) { - return reHasUnicodeWord.test(string); - } - - /** - * Converts `iterator` to an array. - * - * @private - * @param {Object} iterator The iterator to convert. - * @returns {Array} Returns the converted array. - */ - function iteratorToArray(iterator) { - var data, - result = []; - - while (!(data = iterator.next()).done) { - result.push(data.value); - } - return result; - } - - /** - * Converts `map` to its key-value pairs. - * - * @private - * @param {Object} map The map to convert. - * @returns {Array} Returns the key-value pairs. - */ - function mapToArray(map) { - var index = -1, - result = Array(map.size); - - map.forEach(function(value, key) { - result[++index] = [key, value]; - }); - return result; - } - - /** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ - function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; - } - - /** - * Replaces all `placeholder` elements in `array` with an internal placeholder - * and returns an array of their indexes. - * - * @private - * @param {Array} array The array to modify. - * @param {*} placeholder The placeholder to replace. - * @returns {Array} Returns the new array of placeholder indexes. - */ - function replaceHolders(array, placeholder) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value === placeholder || value === PLACEHOLDER) { - array[index] = PLACEHOLDER; - result[resIndex++] = index; - } - } - return result; - } - - /** - * Gets the value at `key`, unless `key` is "__proto__". - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ - function safeGet(object, key) { - return key == '__proto__' - ? undefined - : object[key]; - } - - /** - * Converts `set` to an array of its values. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the values. - */ - function setToArray(set) { - var index = -1, - result = Array(set.size); - - set.forEach(function(value) { - result[++index] = value; - }); - return result; - } - - /** - * Converts `set` to its value-value pairs. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the value-value pairs. - */ - function setToPairs(set) { - var index = -1, - result = Array(set.size); - - set.forEach(function(value) { - result[++index] = [value, value]; - }); - return result; - } - - /** - * A specialized version of `_.indexOf` which performs strict equality - * comparisons of values, i.e. `===`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function strictIndexOf(array, value, fromIndex) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * A specialized version of `_.lastIndexOf` which performs strict equality - * comparisons of values, i.e. `===`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function strictLastIndexOf(array, value, fromIndex) { - var index = fromIndex + 1; - while (index--) { - if (array[index] === value) { - return index; - } - } - return index; - } - - /** - * Gets the number of symbols in `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the string size. - */ - function stringSize(string) { - return hasUnicode(string) - ? unicodeSize(string) - : asciiSize(string); - } - - /** - * Converts `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function stringToArray(string) { - return hasUnicode(string) - ? unicodeToArray(string) - : asciiToArray(string); - } - - /** - * Used by `_.unescape` to convert HTML entities to characters. - * - * @private - * @param {string} chr The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - var unescapeHtmlChar = basePropertyOf(htmlUnescapes); - - /** - * Gets the size of a Unicode `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - function unicodeSize(string) { - var result = reUnicode.lastIndex = 0; - while (reUnicode.test(string)) { - ++result; - } - return result; - } - - /** - * Converts a Unicode `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function unicodeToArray(string) { - return string.match(reUnicode) || []; - } - - /** - * Splits a Unicode `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function unicodeWords(string) { - return string.match(reUnicodeWord) || []; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Create a new pristine `lodash` function using the `context` object. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Util - * @param {Object} [context=root] The context object. - * @returns {Function} Returns a new `lodash` function. - * @example - * - * _.mixin({ 'foo': _.constant('foo') }); - * - * var lodash = _.runInContext(); - * lodash.mixin({ 'bar': lodash.constant('bar') }); - * - * _.isFunction(_.foo); - * // => true - * _.isFunction(_.bar); - * // => false - * - * lodash.isFunction(lodash.foo); - * // => false - * lodash.isFunction(lodash.bar); - * // => true - * - * // Create a suped-up `defer` in Node.js. - * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; - */ - var runInContext = (function runInContext(context) { - context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); - - /** Built-in constructor references. */ - var Array = context.Array, - Date = context.Date, - Error = context.Error, - Function = context.Function, - Math = context.Math, - Object = context.Object, - RegExp = context.RegExp, - String = context.String, - TypeError = context.TypeError; - - /** Used for built-in method references. */ - var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.prototype; - - /** Used to detect overreaching core-js shims. */ - var coreJsData = context['__core-js_shared__']; - - /** Used to resolve the decompiled source of functions. */ - var funcToString = funcProto.toString; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - - /** Used to generate unique IDs. */ - var idCounter = 0; - - /** Used to detect methods masquerading as native. */ - var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; - }()); - - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var nativeObjectToString = objectProto.toString; - - /** Used to infer the `Object` constructor. */ - var objectCtorString = funcToString.call(Object); - - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = root._; - - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); - - /** Built-in value references. */ - var Buffer = moduleExports ? context.Buffer : undefined, - Symbol = context.Symbol, - Uint8Array = context.Uint8Array, - allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, - getPrototype = overArg(Object.getPrototypeOf, Object), - objectCreate = Object.create, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - splice = arrayProto.splice, - spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, - symIterator = Symbol ? Symbol.iterator : undefined, - symToStringTag = Symbol ? Symbol.toStringTag : undefined; - - var defineProperty = (function() { - try { - var func = getNative(Object, 'defineProperty'); - func({}, '', {}); - return func; - } catch (e) {} - }()); - - /** Mocked built-ins. */ - var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, - ctxNow = Date && Date.now !== root.Date.now && Date.now, - ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; - - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeCeil = Math.ceil, - nativeFloor = Math.floor, - nativeGetSymbols = Object.getOwnPropertySymbols, - nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, - nativeIsFinite = context.isFinite, - nativeJoin = arrayProto.join, - nativeKeys = overArg(Object.keys, Object), - nativeMax = Math.max, - nativeMin = Math.min, - nativeNow = Date.now, - nativeParseInt = context.parseInt, - nativeRandom = Math.random, - nativeReverse = arrayProto.reverse; - - /* Built-in method references that are verified to be native. */ - var DataView = getNative(context, 'DataView'), - Map = getNative(context, 'Map'), - Promise = getNative(context, 'Promise'), - Set = getNative(context, 'Set'), - WeakMap = getNative(context, 'WeakMap'), - nativeCreate = getNative(Object, 'create'); - - /** Used to store function metadata. */ - var metaMap = WeakMap && new WeakMap; - - /** Used to lookup unminified function names. */ - var realNames = {}; - - /** Used to detect maps, sets, and weakmaps. */ - var dataViewCtorString = toSource(DataView), - mapCtorString = toSource(Map), - promiseCtorString = toSource(Promise), - setCtorString = toSource(Set), - weakMapCtorString = toSource(WeakMap); - - /** Used to convert symbols to primitives and strings. */ - var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object which wraps `value` to enable implicit method - * chain sequences. Methods that operate on and return arrays, collections, - * and functions can be chained together. Methods that retrieve a single value - * or may return a primitive value will automatically end the chain sequence - * and return the unwrapped value. Otherwise, the value must be unwrapped - * with `_#value`. - * - * Explicit chain sequences, which must be unwrapped with `_#value`, may be - * enabled using `_.chain`. - * - * The execution of chained methods is lazy, that is, it's deferred until - * `_#value` is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. - * Shortcut fusion is an optimization to merge iteratee calls; this avoids - * the creation of intermediate arrays and can greatly reduce the number of - * iteratee executions. Sections of a chain sequence qualify for shortcut - * fusion if the section is applied to an array and iteratees accept only - * one argument. The heuristic for whether a section qualifies for shortcut - * fusion is subject to change. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, - * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, - * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, - * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, - * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, - * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, - * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, - * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, - * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, - * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, - * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, - * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, - * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, - * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, - * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, - * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, - * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, - * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, - * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, - * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, - * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, - * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, - * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, - * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, - * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, - * `zipObject`, `zipObjectDeep`, and `zipWith` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, - * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, - * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, - * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, - * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, - * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, - * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, - * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, - * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, - * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, - * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, - * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, - * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, - * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, - * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, - * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, - * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, - * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, - * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, - * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, - * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, - * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, - * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, - * `upperFirst`, `value`, and `words` - * - * @name _ - * @constructor - * @category Seq - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2, 3]); - * - * // Returns an unwrapped value. - * wrapped.reduce(_.add); - * // => 6 - * - * // Returns a wrapped value. - * var squares = wrapped.map(square); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { - if (value instanceof LodashWrapper) { - return value; - } - if (hasOwnProperty.call(value, '__wrapped__')) { - return wrapperClone(value); - } - } - return new LodashWrapper(value); - } - - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} proto The object to inherit from. - * @returns {Object} Returns the new object. - */ - var baseCreate = (function() { - function object() {} - return function(proto) { - if (!isObject(proto)) { - return {}; - } - if (objectCreate) { - return objectCreate(proto); - } - object.prototype = proto; - var result = new object; - object.prototype = undefined; - return result; - }; - }()); - - /** - * The function whose prototype chain sequence wrappers inherit from. - * - * @private - */ - function baseLodash() { - // No operation performed. - } - - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable explicit method chain sequences. - */ - function LodashWrapper(value, chainAll) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__chain__ = !!chainAll; - this.__index__ = 0; - this.__values__ = undefined; - } - - /** - * By default, the template delimiters used by lodash are like those in - * embedded Ruby (ERB) as well as ES2015 template strings. Change the - * following template settings to use alternative delimiters. - * - * @static - * @memberOf _ - * @type {Object} - */ - lodash.templateSettings = { - - /** - * Used to detect `data` property values to be HTML-escaped. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'escape': reEscape, - - /** - * Used to detect code to be evaluated. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'evaluate': reEvaluate, - - /** - * Used to detect `data` property values to inject. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'interpolate': reInterpolate, - - /** - * Used to reference the data object in the template text. - * - * @memberOf _.templateSettings - * @type {string} - */ - 'variable': '', - - /** - * Used to import variables into the compiled template. - * - * @memberOf _.templateSettings - * @type {Object} - */ - 'imports': { - - /** - * A reference to the `lodash` function. - * - * @memberOf _.templateSettings.imports - * @type {Function} - */ - '_': lodash - } - }; - - // Ensure wrappers are instances of `baseLodash`. - lodash.prototype = baseLodash.prototype; - lodash.prototype.constructor = lodash; - - LodashWrapper.prototype = baseCreate(baseLodash.prototype); - LodashWrapper.prototype.constructor = LodashWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. - * - * @private - * @constructor - * @param {*} value The value to wrap. - */ - function LazyWrapper(value) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__dir__ = 1; - this.__filtered__ = false; - this.__iteratees__ = []; - this.__takeCount__ = MAX_ARRAY_LENGTH; - this.__views__ = []; - } - - /** - * Creates a clone of the lazy wrapper object. - * - * @private - * @name clone - * @memberOf LazyWrapper - * @returns {Object} Returns the cloned `LazyWrapper` object. - */ - function lazyClone() { - var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = copyArray(this.__actions__); - result.__dir__ = this.__dir__; - result.__filtered__ = this.__filtered__; - result.__iteratees__ = copyArray(this.__iteratees__); - result.__takeCount__ = this.__takeCount__; - result.__views__ = copyArray(this.__views__); - return result; - } - - /** - * Reverses the direction of lazy iteration. - * - * @private - * @name reverse - * @memberOf LazyWrapper - * @returns {Object} Returns the new reversed `LazyWrapper` object. - */ - function lazyReverse() { - if (this.__filtered__) { - var result = new LazyWrapper(this); - result.__dir__ = -1; - result.__filtered__ = true; - } else { - result = this.clone(); - result.__dir__ *= -1; - } - return result; - } - - /** - * Extracts the unwrapped value from its lazy wrapper. - * - * @private - * @name value - * @memberOf LazyWrapper - * @returns {*} Returns the unwrapped value. - */ - function lazyValue() { - var array = this.__wrapped__.value(), - dir = this.__dir__, - isArr = isArray(array), - isRight = dir < 0, - arrLength = isArr ? array.length : 0, - view = getView(0, arrLength, this.__views__), - start = view.start, - end = view.end, - length = end - start, - index = isRight ? end : (start - 1), - iteratees = this.__iteratees__, - iterLength = iteratees.length, - resIndex = 0, - takeCount = nativeMin(length, this.__takeCount__); - - if (!isArr || (!isRight && arrLength == length && takeCount == length)) { - return baseWrapperValue(array, this.__actions__); - } - var result = []; - - outer: - while (length-- && resIndex < takeCount) { - index += dir; - - var iterIndex = -1, - value = array[index]; - - while (++iterIndex < iterLength) { - var data = iteratees[iterIndex], - iteratee = data.iteratee, - type = data.type, - computed = iteratee(value); - - if (type == LAZY_MAP_FLAG) { - value = computed; - } else if (!computed) { - if (type == LAZY_FILTER_FLAG) { - continue outer; - } else { - break outer; - } - } - } - result[resIndex++] = value; - } - return result; - } - - // Ensure `LazyWrapper` is an instance of `baseLodash`. - LazyWrapper.prototype = baseCreate(baseLodash.prototype); - LazyWrapper.prototype.constructor = LazyWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a hash object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Hash(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the hash. - * - * @private - * @name clear - * @memberOf Hash - */ - function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; - } - - /** - * Removes `key` and its value from the hash. - * - * @private - * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; - this.size -= result ? 1 : 0; - return result; - } - - /** - * Gets the hash value for `key`. - * - * @private - * @name get - * @memberOf Hash - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; - } - - /** - * Checks if a hash value for `key` exists. - * - * @private - * @name has - * @memberOf Hash - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function hashHas(key) { - var data = this.__data__; - return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); - } - - /** - * Sets the hash `key` to `value`. - * - * @private - * @name set - * @memberOf Hash - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. - */ - function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; - return this; - } - - // Add methods to `Hash`. - Hash.prototype.clear = hashClear; - Hash.prototype['delete'] = hashDelete; - Hash.prototype.get = hashGet; - Hash.prototype.has = hashHas; - Hash.prototype.set = hashSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an list cache object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function ListCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the list cache. - * - * @private - * @name clear - * @memberOf ListCache - */ - function listCacheClear() { - this.__data__ = []; - this.size = 0; - } - - /** - * Removes `key` and its value from the list cache. - * - * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - --this.size; - return true; - } - - /** - * Gets the list cache value for `key`. - * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - return index < 0 ? undefined : data[index][1]; - } - - /** - * Checks if a list cache value for `key` exists. - * - * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; - } - - /** - * Sets the list cache `key` to `value`. - * - * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. - */ - function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; - } - - // Add methods to `ListCache`. - ListCache.prototype.clear = listCacheClear; - ListCache.prototype['delete'] = listCacheDelete; - ListCache.prototype.get = listCacheGet; - ListCache.prototype.has = listCacheHas; - ListCache.prototype.set = listCacheSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function MapCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the map. - * - * @private - * @name clear - * @memberOf MapCache - */ - function mapCacheClear() { - this.size = 0; - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash - }; - } - - /** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function mapCacheDelete(key) { - var result = getMapData(this, key)['delete'](key); - this.size -= result ? 1 : 0; - return result; - } - - /** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function mapCacheGet(key) { - return getMapData(this, key).get(key); - } - - /** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapCacheHas(key) { - return getMapData(this, key).has(key); - } - - /** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ - function mapCacheSet(key, value) { - var data = getMapData(this, key), - size = data.size; - - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; - } - - // Add methods to `MapCache`. - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype['delete'] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; - - /*------------------------------------------------------------------------*/ - - /** - * - * Creates an array cache object to store unique values. - * - * @private - * @constructor - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var index = -1, - length = values == null ? 0 : values.length; - - this.__data__ = new MapCache; - while (++index < length) { - this.add(values[index]); - } - } - - /** - * Adds `value` to the array cache. - * - * @private - * @name add - * @memberOf SetCache - * @alias push - * @param {*} value The value to cache. - * @returns {Object} Returns the cache instance. - */ - function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; - } - - /** - * Checks if `value` is in the array cache. - * - * @private - * @name has - * @memberOf SetCache - * @param {*} value The value to search for. - * @returns {number} Returns `true` if `value` is found, else `false`. - */ - function setCacheHas(value) { - return this.__data__.has(value); - } - - // Add methods to `SetCache`. - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a stack cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Stack(entries) { - var data = this.__data__ = new ListCache(entries); - this.size = data.size; - } - - /** - * Removes all key-value entries from the stack. - * - * @private - * @name clear - * @memberOf Stack - */ - function stackClear() { - this.__data__ = new ListCache; - this.size = 0; - } - - /** - * Removes `key` and its value from the stack. - * - * @private - * @name delete - * @memberOf Stack - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function stackDelete(key) { - var data = this.__data__, - result = data['delete'](key); - - this.size = data.size; - return result; - } - - /** - * Gets the stack value for `key`. - * - * @private - * @name get - * @memberOf Stack - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function stackGet(key) { - return this.__data__.get(key); - } - - /** - * Checks if a stack value for `key` exists. - * - * @private - * @name has - * @memberOf Stack - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function stackHas(key) { - return this.__data__.has(key); - } - - /** - * Sets the stack `key` to `value`. - * - * @private - * @name set - * @memberOf Stack - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the stack cache instance. - */ - function stackSet(key, value) { - var data = this.__data__; - if (data instanceof ListCache) { - var pairs = data.__data__; - if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { - pairs.push([key, value]); - this.size = ++data.size; - return this; - } - data = this.__data__ = new MapCache(pairs); - } - data.set(key, value); - this.size = data.size; - return this; - } - - // Add methods to `Stack`. - Stack.prototype.clear = stackClear; - Stack.prototype['delete'] = stackDelete; - Stack.prototype.get = stackGet; - Stack.prototype.has = stackHas; - Stack.prototype.set = stackSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ - function arrayLikeKeys(value, inherited) { - var isArr = isArray(value), - isArg = !isArr && isArguments(value), - isBuff = !isArr && !isArg && isBuffer(value), - isType = !isArr && !isArg && !isBuff && isTypedArray(value), - skipIndexes = isArr || isArg || isBuff || isType, - result = skipIndexes ? baseTimes(value.length, String) : [], - length = result.length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && ( - // Safari 9 has enumerable `arguments.length` in strict mode. - key == 'length' || - // Node.js 0.10 has enumerable non-index properties on buffers. - (isBuff && (key == 'offset' || key == 'parent')) || - // PhantomJS 2 has enumerable non-index properties on typed arrays. - (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || - // Skip index properties. - isIndex(key, length) - ))) { - result.push(key); - } - } - return result; - } - - /** - * A specialized version of `_.sample` for arrays. - * - * @private - * @param {Array} array The array to sample. - * @returns {*} Returns the random element. - */ - function arraySample(array) { - var length = array.length; - return length ? array[baseRandom(0, length - 1)] : undefined; - } - - /** - * A specialized version of `_.sampleSize` for arrays. - * - * @private - * @param {Array} array The array to sample. - * @param {number} n The number of elements to sample. - * @returns {Array} Returns the random elements. - */ - function arraySampleSize(array, n) { - return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); - } - - /** - * A specialized version of `_.shuffle` for arrays. - * - * @private - * @param {Array} array The array to shuffle. - * @returns {Array} Returns the new shuffled array. - */ - function arrayShuffle(array) { - return shuffleSelf(copyArray(array)); - } - - /** - * This function is like `assignValue` except that it doesn't assign - * `undefined` values. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignMergeValue(object, key, value) { - if ((value !== undefined && !eq(object[key], value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } - } - - /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } - } - - /** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; - } - } - return -1; - } - - /** - * Aggregates elements of `collection` on `accumulator` with keys transformed - * by `iteratee` and values set by `setter`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform keys. - * @param {Object} accumulator The initial aggregated object. - * @returns {Function} Returns `accumulator`. - */ - function baseAggregator(collection, setter, iteratee, accumulator) { - baseEach(collection, function(value, key, collection) { - setter(accumulator, value, iteratee(value), collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.assign` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssign(object, source) { - return object && copyObject(source, keys(source), object); - } - - /** - * The base implementation of `_.assignIn` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssignIn(object, source) { - return object && copyObject(source, keysIn(source), object); - } - - /** - * The base implementation of `assignValue` and `assignMergeValue` without - * value checks. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function baseAssignValue(object, key, value) { - if (key == '__proto__' && defineProperty) { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': true, - 'value': value, - 'writable': true - }); - } else { - object[key] = value; - } - } - - /** - * The base implementation of `_.at` without support for individual paths. - * - * @private - * @param {Object} object The object to iterate over. - * @param {string[]} paths The property paths to pick. - * @returns {Array} Returns the picked elements. - */ - function baseAt(object, paths) { - var index = -1, - length = paths.length, - result = Array(length), - skip = object == null; - - while (++index < length) { - result[index] = skip ? undefined : get(object, paths[index]); - } - return result; - } - - /** - * The base implementation of `_.clamp` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - */ - function baseClamp(number, lower, upper) { - if (number === number) { - if (upper !== undefined) { - number = number <= upper ? number : upper; - } - if (lower !== undefined) { - number = number >= lower ? number : lower; - } - } - return number; - } - - /** - * The base implementation of `_.clone` and `_.cloneDeep` which tracks - * traversed objects. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} bitmask The bitmask flags. - * 1 - Deep clone - * 2 - Flatten inherited properties - * 4 - Clone symbols - * @param {Function} [customizer] The function to customize cloning. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The parent object of `value`. - * @param {Object} [stack] Tracks traversed objects and their clone counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, bitmask, customizer, key, object, stack) { - var result, - isDeep = bitmask & CLONE_DEEP_FLAG, - isFlat = bitmask & CLONE_FLAT_FLAG, - isFull = bitmask & CLONE_SYMBOLS_FLAG; - - if (customizer) { - result = object ? customizer(value, key, object, stack) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return copyArray(value, result); - } - } else { - var tag = getTag(value), - isFunc = tag == funcTag || tag == genTag; - - if (isBuffer(value)) { - return cloneBuffer(value, isDeep); - } - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - result = (isFlat || isFunc) ? {} : initCloneObject(value); - if (!isDeep) { - return isFlat - ? copySymbolsIn(value, baseAssignIn(result, value)) - : copySymbols(value, baseAssign(result, value)); - } - } else { - if (!cloneableTags[tag]) { - return object ? value : {}; - } - result = initCloneByTag(value, tag, isDeep); - } - } - // Check for circular references and return its corresponding clone. - stack || (stack = new Stack); - var stacked = stack.get(value); - if (stacked) { - return stacked; - } - stack.set(value, result); - - if (isSet(value)) { - value.forEach(function(subValue) { - result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); - }); - - return result; - } - - if (isMap(value)) { - value.forEach(function(subValue, key) { - result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); - }); - - return result; - } - - var keysFunc = isFull - ? (isFlat ? getAllKeysIn : getAllKeys) - : (isFlat ? keysIn : keys); - - var props = isArr ? undefined : keysFunc(value); - arrayEach(props || value, function(subValue, key) { - if (props) { - key = subValue; - subValue = value[key]; - } - // Recursively populate clone (susceptible to call stack limits). - assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); - }); - return result; - } - - /** - * The base implementation of `_.conforms` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property predicates to conform to. - * @returns {Function} Returns the new spec function. - */ - function baseConforms(source) { - var props = keys(source); - return function(object) { - return baseConformsTo(object, source, props); - }; - } - - /** - * The base implementation of `_.conformsTo` which accepts `props` to check. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - */ - function baseConformsTo(object, source, props) { - var length = props.length; - if (object == null) { - return !length; - } - object = Object(object); - while (length--) { - var key = props[length], - predicate = source[key], - value = object[key]; - - if ((value === undefined && !(key in object)) || !predicate(value)) { - return false; - } - } - return true; - } - - /** - * The base implementation of `_.delay` and `_.defer` which accepts `args` - * to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Array} args The arguments to provide to `func`. - * @returns {number|Object} Returns the timer id or timeout object. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return setTimeout(function() { func.apply(undefined, args); }, wait); - } - - /** - * The base implementation of methods like `_.difference` without support - * for excluding multiple arrays or iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Array} values The values to exclude. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - */ - function baseDifference(array, values, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - isCommon = true, - length = array.length, - result = [], - valuesLength = values.length; - - if (!length) { - return result; - } - if (iteratee) { - values = arrayMap(values, baseUnary(iteratee)); - } - if (comparator) { - includes = arrayIncludesWith; - isCommon = false; - } - else if (values.length >= LARGE_ARRAY_SIZE) { - includes = cacheHas; - isCommon = false; - values = new SetCache(values); - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee == null ? value : iteratee(value); - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === computed) { - continue outer; - } - } - result.push(value); - } - else if (!includes(values, computed, comparator)) { - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.forEach` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); - - /** - * The base implementation of `_.forEachRight` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEachRight = createBaseEach(baseForOwnRight, true); - - /** - * The base implementation of `_.every` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false` - */ - function baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function(value, index, collection) { - result = !!predicate(value, index, collection); - return result; - }); - return result; - } - - /** - * The base implementation of methods like `_.max` and `_.min` which accepts a - * `comparator` to determine the extremum value. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The iteratee invoked per iteration. - * @param {Function} comparator The comparator used to compare values. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(array, iteratee, comparator) { - var index = -1, - length = array.length; - - while (++index < length) { - var value = array[index], - current = iteratee(value); - - if (current != null && (computed === undefined - ? (current === current && !isSymbol(current)) - : comparator(current, computed) - )) { - var computed = current, - result = value; - } - } - return result; - } - - /** - * The base implementation of `_.fill` without an iteratee call guard. - * - * @private - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - */ - function baseFill(array, value, start, end) { - var length = array.length; - - start = toInteger(start); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : toInteger(end); - if (end < 0) { - end += length; - } - end = start > end ? 0 : toLength(end); - while (start < end) { - array[start++] = value; - } - return array; - } - - /** - * The base implementation of `_.filter` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } - - /** - * The base implementation of `_.flatten` with support for restricting flattening. - * - * @private - * @param {Array} array The array to flatten. - * @param {number} depth The maximum recursion depth. - * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. - * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); - - while (++index < length) { - var value = array[index]; - if (depth > 0 && predicate(value)) { - if (depth > 1) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, predicate, isStrict, result); - } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } - } - return result; - } - - /** - * The base implementation of `baseForOwn` which iterates over `object` - * properties returned by `keysFunc` and invokes `iteratee` for each property. - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); - - /** - * This function is like `baseFor` except that it iterates over properties - * in the opposite order. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseForRight = createBaseFor(true); - - /** - * The base implementation of `_.forOwn` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return object && baseFor(object, iteratee, keys); - } - - /** - * The base implementation of `_.forOwnRight` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwnRight(object, iteratee) { - return object && baseForRight(object, iteratee, keys); - } - - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from `props`. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the function names. - */ - function baseFunctions(object, props) { - return arrayFilter(props, function(key) { - return isFunction(object[key]); - }); - } - - /** - * The base implementation of `_.get` without support for default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path) { - path = castPath(path, object); - - var index = 0, - length = path.length; - - while (object != null && index < length) { - object = object[toKey(path[index++])]; - } - return (index && index == length) ? object : undefined; - } - - /** - * The base implementation of `getAllKeys` and `getAllKeysIn` which uses - * `keysFunc` and `symbolsFunc` to get the enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Function} keysFunc The function to get the keys of `object`. - * @param {Function} symbolsFunc The function to get the symbols of `object`. - * @returns {Array} Returns the array of property names and symbols. - */ - function baseGetAllKeys(object, keysFunc, symbolsFunc) { - var result = keysFunc(object); - return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); - } - - /** - * The base implementation of `getTag` without fallbacks for buggy environments. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - function baseGetTag(value) { - if (value == null) { - return value === undefined ? undefinedTag : nullTag; - } - return (symToStringTag && symToStringTag in Object(value)) - ? getRawTag(value) - : objectToString(value); - } - - /** - * The base implementation of `_.gt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - */ - function baseGt(value, other) { - return value > other; - } - - /** - * The base implementation of `_.has` without support for deep paths. - * - * @private - * @param {Object} [object] The object to query. - * @param {Array|string} key The key to check. - * @returns {boolean} Returns `true` if `key` exists, else `false`. - */ - function baseHas(object, key) { - return object != null && hasOwnProperty.call(object, key); - } - - /** - * The base implementation of `_.hasIn` without support for deep paths. - * - * @private - * @param {Object} [object] The object to query. - * @param {Array|string} key The key to check. - * @returns {boolean} Returns `true` if `key` exists, else `false`. - */ - function baseHasIn(object, key) { - return object != null && key in Object(object); - } - - /** - * The base implementation of `_.inRange` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to check. - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - */ - function baseInRange(number, start, end) { - return number >= nativeMin(start, end) && number < nativeMax(start, end); - } - - /** - * The base implementation of methods like `_.intersection`, without support - * for iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of shared values. - */ - function baseIntersection(arrays, iteratee, comparator) { - var includes = comparator ? arrayIncludesWith : arrayIncludes, - length = arrays[0].length, - othLength = arrays.length, - othIndex = othLength, - caches = Array(othLength), - maxLength = Infinity, - result = []; - - while (othIndex--) { - var array = arrays[othIndex]; - if (othIndex && iteratee) { - array = arrayMap(array, baseUnary(iteratee)); - } - maxLength = nativeMin(array.length, maxLength); - caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) - ? new SetCache(othIndex && array) - : undefined; - } - array = arrays[0]; - - var index = -1, - seen = caches[0]; - - outer: - while (++index < length && result.length < maxLength) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (!(seen - ? cacheHas(seen, computed) - : includes(result, computed, comparator) - )) { - othIndex = othLength; - while (--othIndex) { - var cache = caches[othIndex]; - if (!(cache - ? cacheHas(cache, computed) - : includes(arrays[othIndex], computed, comparator)) - ) { - continue outer; - } - } - if (seen) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.invert` and `_.invertBy` which inverts - * `object` with values transformed by `iteratee` and set by `setter`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform values. - * @param {Object} accumulator The initial inverted object. - * @returns {Function} Returns `accumulator`. - */ - function baseInverter(object, setter, iteratee, accumulator) { - baseForOwn(object, function(value, key, object) { - setter(accumulator, iteratee(value), key, object); - }); - return accumulator; - } - - /** - * The base implementation of `_.invoke` without support for individual - * method arguments. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - */ - function baseInvoke(object, path, args) { - path = castPath(path, object); - object = parent(object, path); - var func = object == null ? object : object[toKey(last(path))]; - return func == null ? undefined : apply(func, object, args); - } - - /** - * The base implementation of `_.isArguments`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - */ - function baseIsArguments(value) { - return isObjectLike(value) && baseGetTag(value) == argsTag; - } - - /** - * The base implementation of `_.isArrayBuffer` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - */ - function baseIsArrayBuffer(value) { - return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; - } - - /** - * The base implementation of `_.isDate` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - */ - function baseIsDate(value) { - return isObjectLike(value) && baseGetTag(value) == dateTag; - } - - /** - * The base implementation of `_.isEqual` which supports partial comparisons - * and tracks traversed objects. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {boolean} bitmask The bitmask flags. - * 1 - Unordered comparison - * 2 - Partial comparison - * @param {Function} [customizer] The function to customize comparisons. - * @param {Object} [stack] Tracks traversed `value` and `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, bitmask, customizer, stack) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); - } - - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} [stack] Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = objIsArr ? arrayTag : getTag(object), - othTag = othIsArr ? arrayTag : getTag(other); - - objTag = objTag == argsTag ? objectTag : objTag; - othTag = othTag == argsTag ? objectTag : othTag; - - var objIsObj = objTag == objectTag, - othIsObj = othTag == objectTag, - isSameTag = objTag == othTag; - - if (isSameTag && isBuffer(object)) { - if (!isBuffer(other)) { - return false; - } - objIsArr = true; - objIsObj = false; - } - if (isSameTag && !objIsObj) { - stack || (stack = new Stack); - return (objIsArr || isTypedArray(object)) - ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) - : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); - } - if (!(bitmask & COMPARE_PARTIAL_FLAG)) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); - - if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object.value() : object, - othUnwrapped = othIsWrapped ? other.value() : other; - - stack || (stack = new Stack); - return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); - } - } - if (!isSameTag) { - return false; - } - stack || (stack = new Stack); - return equalObjects(object, other, bitmask, customizer, equalFunc, stack); - } - - /** - * The base implementation of `_.isMap` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - */ - function baseIsMap(value) { - return isObjectLike(value) && getTag(value) == mapTag; - } - - /** - * The base implementation of `_.isMatch` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Array} matchData The property names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - */ - function baseIsMatch(object, source, matchData, customizer) { - var index = matchData.length, - length = index, - noCustomizer = !customizer; - - if (object == null) { - return !length; - } - object = Object(object); - while (index--) { - var data = matchData[index]; - if ((noCustomizer && data[2]) - ? data[1] !== object[data[0]] - : !(data[0] in object) - ) { - return false; - } - } - while (++index < length) { - data = matchData[index]; - var key = data[0], - objValue = object[key], - srcValue = data[1]; - - if (noCustomizer && data[2]) { - if (objValue === undefined && !(key in object)) { - return false; - } - } else { - var stack = new Stack; - if (customizer) { - var result = customizer(objValue, srcValue, key, object, source, stack); - } - if (!(result === undefined - ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) - : result - )) { - return false; - } - } - } - return true; - } - - /** - * The base implementation of `_.isNative` without bad shim checks. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - */ - function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); - } - - /** - * The base implementation of `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ - function baseIsRegExp(value) { - return isObjectLike(value) && baseGetTag(value) == regexpTag; - } - - /** - * The base implementation of `_.isSet` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - */ - function baseIsSet(value) { - return isObjectLike(value) && getTag(value) == setTag; - } - - /** - * The base implementation of `_.isTypedArray` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - */ - function baseIsTypedArray(value) { - return isObjectLike(value) && - isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; - } - - /** - * The base implementation of `_.iteratee`. - * - * @private - * @param {*} [value=_.identity] The value to convert to an iteratee. - * @returns {Function} Returns the iteratee. - */ - function baseIteratee(value) { - // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. - // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. - if (typeof value == 'function') { - return value; - } - if (value == null) { - return identity; - } - if (typeof value == 'object') { - return isArray(value) - ? baseMatchesProperty(value[0], value[1]) - : baseMatches(value); - } - return property(value); - } - - /** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeysIn(object) { - if (!isObject(object)) { - return nativeKeysIn(object); - } - var isProto = isPrototype(object), - result = []; - - for (var key in object) { - if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.lt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - */ - function baseLt(value, other) { - return value < other; - } - - /** - * The base implementation of `_.map` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value, key, collection) { - result[++index] = iteratee(value, key, collection); - }); - return result; - } - - /** - * The base implementation of `_.matches` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatches(source) { - var matchData = getMatchData(source); - if (matchData.length == 1 && matchData[0][2]) { - return matchesStrictComparable(matchData[0][0], matchData[0][1]); - } - return function(object) { - return object === source || baseIsMatch(object, source, matchData); - }; - } - - /** - * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. - * - * @private - * @param {string} path The path of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatchesProperty(path, srcValue) { - if (isKey(path) && isStrictComparable(srcValue)) { - return matchesStrictComparable(toKey(path), srcValue); - } - return function(object) { - var objValue = get(object, path); - return (objValue === undefined && objValue === srcValue) - ? hasIn(object, path) - : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); - }; - } - - /** - * The base implementation of `_.merge` without support for multiple sources. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {number} srcIndex The index of `source`. - * @param {Function} [customizer] The function to customize merged values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMerge(object, source, srcIndex, customizer, stack) { - if (object === source) { - return; - } - baseFor(source, function(srcValue, key) { - if (isObject(srcValue)) { - stack || (stack = new Stack); - baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); - } - else { - var newValue = customizer - ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) - : undefined; - - if (newValue === undefined) { - newValue = srcValue; - } - assignMergeValue(object, key, newValue); - } - }, keysIn); - } - - /** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {number} srcIndex The index of `source`. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize assigned values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { - var objValue = safeGet(object, key), - srcValue = safeGet(source, key), - stacked = stack.get(srcValue); - - if (stacked) { - assignMergeValue(object, key, stacked); - return; - } - var newValue = customizer - ? customizer(objValue, srcValue, (key + ''), object, source, stack) - : undefined; - - var isCommon = newValue === undefined; - - if (isCommon) { - var isArr = isArray(srcValue), - isBuff = !isArr && isBuffer(srcValue), - isTyped = !isArr && !isBuff && isTypedArray(srcValue); - - newValue = srcValue; - if (isArr || isBuff || isTyped) { - if (isArray(objValue)) { - newValue = objValue; - } - else if (isArrayLikeObject(objValue)) { - newValue = copyArray(objValue); - } - else if (isBuff) { - isCommon = false; - newValue = cloneBuffer(srcValue, true); - } - else if (isTyped) { - isCommon = false; - newValue = cloneTypedArray(srcValue, true); - } - else { - newValue = []; - } - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - newValue = objValue; - if (isArguments(objValue)) { - newValue = toPlainObject(objValue); - } - else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { - newValue = initCloneObject(srcValue); - } - } - else { - isCommon = false; - } - } - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, newValue); - mergeFunc(newValue, srcValue, srcIndex, customizer, stack); - stack['delete'](srcValue); - } - assignMergeValue(object, key, newValue); - } - - /** - * The base implementation of `_.nth` which doesn't coerce arguments. - * - * @private - * @param {Array} array The array to query. - * @param {number} n The index of the element to return. - * @returns {*} Returns the nth element of `array`. - */ - function baseNth(array, n) { - var length = array.length; - if (!length) { - return; - } - n += n < 0 ? length : 0; - return isIndex(n, length) ? array[n] : undefined; - } - - /** - * The base implementation of `_.orderBy` without param guards. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {string[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseOrderBy(collection, iteratees, orders) { - var index = -1; - iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); - - var result = baseMap(collection, function(value, key, collection) { - var criteria = arrayMap(iteratees, function(iteratee) { - return iteratee(value); - }); - return { 'criteria': criteria, 'index': ++index, 'value': value }; - }); - - return baseSortBy(result, function(object, other) { - return compareMultiple(object, other, orders); - }); - } - - /** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @returns {Object} Returns the new object. - */ - function basePick(object, paths) { - return basePickBy(object, paths, function(value, path) { - return hasIn(object, path); - }); - } - - /** - * The base implementation of `_.pickBy` without support for iteratee shorthands. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @param {Function} predicate The function invoked per property. - * @returns {Object} Returns the new object. - */ - function basePickBy(object, paths, predicate) { - var index = -1, - length = paths.length, - result = {}; - - while (++index < length) { - var path = paths[index], - value = baseGet(object, path); - - if (predicate(value, path)) { - baseSet(result, castPath(path, object), value); - } - } - return result; - } - - /** - * A specialized version of `baseProperty` which supports deep paths. - * - * @private - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyDeep(path) { - return function(object) { - return baseGet(object, path); - }; - } - - /** - * The base implementation of `_.pullAllBy` without support for iteratee - * shorthands. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - */ - function basePullAll(array, values, iteratee, comparator) { - var indexOf = comparator ? baseIndexOfWith : baseIndexOf, - index = -1, - length = values.length, - seen = array; - - if (array === values) { - values = copyArray(values); - } - if (iteratee) { - seen = arrayMap(array, baseUnary(iteratee)); - } - while (++index < length) { - var fromIndex = 0, - value = values[index], - computed = iteratee ? iteratee(value) : value; - - while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { - if (seen !== array) { - splice.call(seen, fromIndex, 1); - } - splice.call(array, fromIndex, 1); - } - } - return array; - } - - /** - * The base implementation of `_.pullAt` without support for individual - * indexes or capturing the removed elements. - * - * @private - * @param {Array} array The array to modify. - * @param {number[]} indexes The indexes of elements to remove. - * @returns {Array} Returns `array`. - */ - function basePullAt(array, indexes) { - var length = array ? indexes.length : 0, - lastIndex = length - 1; - - while (length--) { - var index = indexes[length]; - if (length == lastIndex || index !== previous) { - var previous = index; - if (isIndex(index)) { - splice.call(array, index, 1); - } else { - baseUnset(array, index); - } - } - } - return array; - } - - /** - * The base implementation of `_.random` without support for returning - * floating-point numbers. - * - * @private - * @param {number} lower The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the random number. - */ - function baseRandom(lower, upper) { - return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); - } - - /** - * The base implementation of `_.range` and `_.rangeRight` which doesn't - * coerce arguments. - * - * @private - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @param {number} step The value to increment or decrement by. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the range of numbers. - */ - function baseRange(start, end, step, fromRight) { - var index = -1, - length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), - result = Array(length); - - while (length--) { - result[fromRight ? length : ++index] = start; - start += step; - } - return result; - } - - /** - * The base implementation of `_.repeat` which doesn't coerce arguments. - * - * @private - * @param {string} string The string to repeat. - * @param {number} n The number of times to repeat the string. - * @returns {string} Returns the repeated string. - */ - function baseRepeat(string, n) { - var result = ''; - if (!string || n < 1 || n > MAX_SAFE_INTEGER) { - return result; - } - // Leverage the exponentiation by squaring algorithm for a faster repeat. - // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. - do { - if (n % 2) { - result += string; - } - n = nativeFloor(n / 2); - if (n) { - string += string; - } - } while (n); - - return result; - } - - /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ - function baseRest(func, start) { - return setToString(overRest(func, start, identity), func + ''); - } - - /** - * The base implementation of `_.sample`. - * - * @private - * @param {Array|Object} collection The collection to sample. - * @returns {*} Returns the random element. - */ - function baseSample(collection) { - return arraySample(values(collection)); - } - - /** - * The base implementation of `_.sampleSize` without param guards. - * - * @private - * @param {Array|Object} collection The collection to sample. - * @param {number} n The number of elements to sample. - * @returns {Array} Returns the random elements. - */ - function baseSampleSize(collection, n) { - var array = values(collection); - return shuffleSelf(array, baseClamp(n, 0, array.length)); - } - - /** - * The base implementation of `_.set`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseSet(object, path, value, customizer) { - if (!isObject(object)) { - return object; - } - path = castPath(path, object); - - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; - - while (nested != null && ++index < length) { - var key = toKey(path[index]), - newValue = value; - - if (index != lastIndex) { - var objValue = nested[key]; - newValue = customizer ? customizer(objValue, key, nested) : undefined; - if (newValue === undefined) { - newValue = isObject(objValue) - ? objValue - : (isIndex(path[index + 1]) ? [] : {}); - } - } - assignValue(nested, key, newValue); - nested = nested[key]; - } - return object; - } - - /** - * The base implementation of `setData` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var baseSetData = !metaMap ? identity : function(func, data) { - metaMap.set(func, data); - return func; - }; - - /** - * The base implementation of `setToString` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ - var baseSetToString = !defineProperty ? identity : function(func, string) { - return defineProperty(func, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(string), - 'writable': true - }); - }; - - /** - * The base implementation of `_.shuffle`. - * - * @private - * @param {Array|Object} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - */ - function baseShuffle(collection) { - return shuffleSelf(values(collection)); - } - - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, - length = array.length; - - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = end > length ? length : end; - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; - - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; - } - - /** - * The base implementation of `_.some` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function baseSome(collection, predicate) { - var result; - - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } - - /** - * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which - * performs a binary search of `array` to determine the index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function baseSortedIndex(array, value, retHighest) { - var low = 0, - high = array == null ? low : array.length; - - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = (low + high) >>> 1, - computed = array[mid]; - - if (computed !== null && !isSymbol(computed) && - (retHighest ? (computed <= value) : (computed < value))) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return baseSortedIndexBy(array, value, identity, retHighest); - } - - /** - * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` - * which invokes `iteratee` for `value` and each element of `array` to compute - * their sort ranking. The iteratee is invoked with one argument; (value). - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} iteratee The iteratee invoked per element. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function baseSortedIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); - - var low = 0, - high = array == null ? 0 : array.length, - valIsNaN = value !== value, - valIsNull = value === null, - valIsSymbol = isSymbol(value), - valIsUndefined = value === undefined; - - while (low < high) { - var mid = nativeFloor((low + high) / 2), - computed = iteratee(array[mid]), - othIsDefined = computed !== undefined, - othIsNull = computed === null, - othIsReflexive = computed === computed, - othIsSymbol = isSymbol(computed); - - if (valIsNaN) { - var setLow = retHighest || othIsReflexive; - } else if (valIsUndefined) { - setLow = othIsReflexive && (retHighest || othIsDefined); - } else if (valIsNull) { - setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); - } else if (valIsSymbol) { - setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); - } else if (othIsNull || othIsSymbol) { - setLow = false; - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } - - /** - * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseSortedUniq(array, iteratee) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - if (!index || !eq(computed, seen)) { - var seen = computed; - result[resIndex++] = value === 0 ? 0 : value; - } - } - return result; - } - - /** - * The base implementation of `_.toNumber` which doesn't ensure correct - * conversions of binary, hexadecimal, or octal string values. - * - * @private - * @param {*} value The value to process. - * @returns {number} Returns the number. - */ - function baseToNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - return +value; - } - - /** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isArray(value)) { - // Recursively convert values (susceptible to call stack limits). - return arrayMap(value, baseToString) + ''; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * The base implementation of `_.uniqBy` without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseUniq(array, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - length = array.length, - isCommon = true, - result = [], - seen = result; - - if (comparator) { - isCommon = false; - includes = arrayIncludesWith; - } - else if (length >= LARGE_ARRAY_SIZE) { - var set = iteratee ? null : createSet(array); - if (set) { - return setToArray(set); - } - isCommon = false; - includes = cacheHas; - seen = new SetCache; - } - else { - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } - } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } - else if (!includes(seen, computed, comparator)) { - if (seen !== result) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.unset`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The property path to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - */ - function baseUnset(object, path) { - path = castPath(path, object); - object = parent(object, path); - return object == null || delete object[toKey(last(path))]; - } - - /** - * The base implementation of `_.update`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to update. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseUpdate(object, path, updater, customizer) { - return baseSet(object, path, updater(baseGet(object, path)), customizer); - } - - /** - * The base implementation of methods like `_.dropWhile` and `_.takeWhile` - * without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to query. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [isDrop] Specify dropping elements instead of taking them. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the slice of `array`. - */ - function baseWhile(array, predicate, isDrop, fromRight) { - var length = array.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length) && - predicate(array[index], index, array)) {} - - return isDrop - ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) - : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); - } - - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to perform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - return arrayReduce(actions, function(result, action) { - return action.func.apply(action.thisArg, arrayPush([result], action.args)); - }, result); - } - - /** - * The base implementation of methods like `_.xor`, without support for - * iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of values. - */ - function baseXor(arrays, iteratee, comparator) { - var length = arrays.length; - if (length < 2) { - return length ? baseUniq(arrays[0]) : []; - } - var index = -1, - result = Array(length); - - while (++index < length) { - var array = arrays[index], - othIndex = -1; - - while (++othIndex < length) { - if (othIndex != index) { - result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); - } - } - } - return baseUniq(baseFlatten(result, 1), iteratee, comparator); - } - - /** - * This base implementation of `_.zipObject` which assigns values using `assignFunc`. - * - * @private - * @param {Array} props The property identifiers. - * @param {Array} values The property values. - * @param {Function} assignFunc The function to assign values. - * @returns {Object} Returns the new object. - */ - function baseZipObject(props, values, assignFunc) { - var index = -1, - length = props.length, - valsLength = values.length, - result = {}; - - while (++index < length) { - var value = index < valsLength ? values[index] : undefined; - assignFunc(result, props[index], value); - } - return result; - } - - /** - * Casts `value` to an empty array if it's not an array like object. - * - * @private - * @param {*} value The value to inspect. - * @returns {Array|Object} Returns the cast array-like object. - */ - function castArrayLikeObject(value) { - return isArrayLikeObject(value) ? value : []; - } - - /** - * Casts `value` to `identity` if it's not a function. - * - * @private - * @param {*} value The value to inspect. - * @returns {Function} Returns cast function. - */ - function castFunction(value) { - return typeof value == 'function' ? value : identity; - } - - /** - * Casts `value` to a path array if it's not one. - * - * @private - * @param {*} value The value to inspect. - * @param {Object} [object] The object to query keys on. - * @returns {Array} Returns the cast property path array. - */ - function castPath(value, object) { - if (isArray(value)) { - return value; - } - return isKey(value, object) ? [value] : stringToPath(toString(value)); - } - - /** - * A `baseRest` alias which can be replaced with `identity` by module - * replacement plugins. - * - * @private - * @type {Function} - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. - */ - var castRest = baseRest; - - /** - * Casts `array` to a slice if it's needed. - * - * @private - * @param {Array} array The array to inspect. - * @param {number} start The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the cast slice. - */ - function castSlice(array, start, end) { - var length = array.length; - end = end === undefined ? length : end; - return (!start && end >= length) ? array : baseSlice(array, start, end); - } - - /** - * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). - * - * @private - * @param {number|Object} id The timer id or timeout object of the timer to clear. - */ - var clearTimeout = ctxClearTimeout || function(id) { - return root.clearTimeout(id); - }; - - /** - * Creates a clone of `buffer`. - * - * @private - * @param {Buffer} buffer The buffer to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Buffer} Returns the cloned buffer. - */ - function cloneBuffer(buffer, isDeep) { - if (isDeep) { - return buffer.slice(); - } - var length = buffer.length, - result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); - - buffer.copy(result); - return result; - } - - /** - * Creates a clone of `arrayBuffer`. - * - * @private - * @param {ArrayBuffer} arrayBuffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ - function cloneArrayBuffer(arrayBuffer) { - var result = new arrayBuffer.constructor(arrayBuffer.byteLength); - new Uint8Array(result).set(new Uint8Array(arrayBuffer)); - return result; - } - - /** - * Creates a clone of `dataView`. - * - * @private - * @param {Object} dataView The data view to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned data view. - */ - function cloneDataView(dataView, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; - return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); - } - - /** - * Creates a clone of `regexp`. - * - * @private - * @param {Object} regexp The regexp to clone. - * @returns {Object} Returns the cloned regexp. - */ - function cloneRegExp(regexp) { - var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); - result.lastIndex = regexp.lastIndex; - return result; - } - - /** - * Creates a clone of the `symbol` object. - * - * @private - * @param {Object} symbol The symbol object to clone. - * @returns {Object} Returns the cloned symbol object. - */ - function cloneSymbol(symbol) { - return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; - } - - /** - * Creates a clone of `typedArray`. - * - * @private - * @param {Object} typedArray The typed array to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned typed array. - */ - function cloneTypedArray(typedArray, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; - return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); - } - - /** - * Compares values to sort them in ascending order. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function compareAscending(value, other) { - if (value !== other) { - var valIsDefined = value !== undefined, - valIsNull = value === null, - valIsReflexive = value === value, - valIsSymbol = isSymbol(value); - - var othIsDefined = other !== undefined, - othIsNull = other === null, - othIsReflexive = other === other, - othIsSymbol = isSymbol(other); - - if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || - (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || - (valIsNull && othIsDefined && othIsReflexive) || - (!valIsDefined && othIsReflexive) || - !valIsReflexive) { - return 1; - } - if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || - (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || - (othIsNull && valIsDefined && valIsReflexive) || - (!othIsDefined && valIsReflexive) || - !othIsReflexive) { - return -1; - } - } - return 0; - } - - /** - * Used by `_.orderBy` to compare multiple properties of a value to another - * and stable sort them. - * - * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, - * specify an order of "desc" for descending or "asc" for ascending sort order - * of corresponding values. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {boolean[]|string[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, - objCriteria = object.criteria, - othCriteria = other.criteria, - length = objCriteria.length, - ordersLength = orders.length; - - while (++index < length) { - var result = compareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; - } - var order = orders[index]; - return result * (order == 'desc' ? -1 : 1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } - - /** - * Creates an array that is the composition of partially applied arguments, - * placeholders, and provided arguments into a single array of arguments. - * - * @private - * @param {Array} args The provided arguments. - * @param {Array} partials The arguments to prepend to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @params {boolean} [isCurried] Specify composing for a curried function. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgs(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersLength = holders.length, - leftIndex = -1, - leftLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(leftLength + rangeLength), - isUncurried = !isCurried; - - while (++leftIndex < leftLength) { - result[leftIndex] = partials[leftIndex]; - } - while (++argsIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[holders[argsIndex]] = args[argsIndex]; - } - } - while (rangeLength--) { - result[leftIndex++] = args[argsIndex++]; - } - return result; - } - - /** - * This function is like `composeArgs` except that the arguments composition - * is tailored for `_.partialRight`. - * - * @private - * @param {Array} args The provided arguments. - * @param {Array} partials The arguments to append to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @params {boolean} [isCurried] Specify composing for a curried function. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgsRight(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersIndex = -1, - holdersLength = holders.length, - rightIndex = -1, - rightLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(rangeLength + rightLength), - isUncurried = !isCurried; - - while (++argsIndex < rangeLength) { - result[argsIndex] = args[argsIndex]; - } - var offset = argsIndex; - while (++rightIndex < rightLength) { - result[offset + rightIndex] = partials[rightIndex]; - } - while (++holdersIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } - } - return result; - } - - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function copyArray(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } - - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ - function copyObject(source, props, object, customizer) { - var isNew = !object; - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; - - if (newValue === undefined) { - newValue = source[key]; - } - if (isNew) { - baseAssignValue(object, key, newValue); - } else { - assignValue(object, key, newValue); - } - } - return object; - } - - /** - * Copies own symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbols(source, object) { - return copyObject(source, getSymbols(source), object); - } - - /** - * Copies own and inherited symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbolsIn(source, object) { - return copyObject(source, getSymbolsIn(source), object); - } - - /** - * Creates a function like `_.groupBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} [initializer] The accumulator object initializer. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter, initializer) { - return function(collection, iteratee) { - var func = isArray(collection) ? arrayAggregator : baseAggregator, - accumulator = initializer ? initializer() : {}; - - return func(collection, setter, getIteratee(iteratee, 2), accumulator); - }; - } - - /** - * Creates a function like `_.assign`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return baseRest(function(object, sources) { - var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined, - guard = length > 2 ? sources[2] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - object = Object(object); - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, index, customizer); - } - } - return object; - }); - } - - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - if (collection == null) { - return collection; - } - if (!isArrayLike(collection)) { - return eachFunc(collection, iteratee); - } - var length = collection.length, - index = fromRight ? length : -1, - iterable = Object(collection); - - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } - - /** - * Creates a base function for methods like `_.forIn` and `_.forOwn`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), - props = keysFunc(object), - length = props.length; - - while (length--) { - var key = props[fromRight ? length : ++index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } - - /** - * Creates a function that wraps `func` to invoke it with the optional `this` - * binding of `thisArg`. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createBind(func, bitmask, thisArg) { - var isBind = bitmask & WRAP_BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(isBind ? thisArg : this, arguments); - } - return wrapper; - } - - /** - * Creates a function like `_.lowerFirst`. - * - * @private - * @param {string} methodName The name of the `String` case method to use. - * @returns {Function} Returns the new case function. - */ - function createCaseFirst(methodName) { - return function(string) { - string = toString(string); - - var strSymbols = hasUnicode(string) - ? stringToArray(string) - : undefined; - - var chr = strSymbols - ? strSymbols[0] - : string.charAt(0); - - var trailing = strSymbols - ? castSlice(strSymbols, 1).join('') - : string.slice(1); - - return chr[methodName]() + trailing; - }; - } - - /** - * Creates a function like `_.camelCase`. - * - * @private - * @param {Function} callback The function to combine each word. - * @returns {Function} Returns the new compounder function. - */ - function createCompounder(callback) { - return function(string) { - return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); - }; - } - - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtor(Ctor) { - return function() { - // Use a `switch` statement to work with class constructors. See - // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist - // for more details. - var args = arguments; - switch (args.length) { - case 0: return new Ctor; - case 1: return new Ctor(args[0]); - case 2: return new Ctor(args[0], args[1]); - case 3: return new Ctor(args[0], args[1], args[2]); - case 4: return new Ctor(args[0], args[1], args[2], args[3]); - case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); - case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); - case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - } - var thisBinding = baseCreate(Ctor.prototype), - result = Ctor.apply(thisBinding, args); - - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } - - /** - * Creates a function that wraps `func` to enable currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {number} arity The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createCurry(func, bitmask, arity) { - var Ctor = createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length, - placeholder = getHolder(wrapper); - - while (index--) { - args[index] = arguments[index]; - } - var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) - ? [] - : replaceHolders(args, placeholder); - - length -= holders.length; - if (length < arity) { - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, undefined, - args, holders, undefined, undefined, arity - length); - } - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return apply(fn, this, args); - } - return wrapper; - } - - /** - * Creates a `_.find` or `_.findLast` function. - * - * @private - * @param {Function} findIndexFunc The function to find the collection index. - * @returns {Function} Returns the new find function. - */ - function createFind(findIndexFunc) { - return function(collection, predicate, fromIndex) { - var iterable = Object(collection); - if (!isArrayLike(collection)) { - var iteratee = getIteratee(predicate, 3); - collection = keys(collection); - predicate = function(key) { return iteratee(iterable[key], key, iterable); }; - } - var index = findIndexFunc(collection, predicate, fromIndex); - return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; - }; - } - - /** - * Creates a `_.flow` or `_.flowRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new flow function. - */ - function createFlow(fromRight) { - return flatRest(function(funcs) { - var length = funcs.length, - index = length, - prereq = LodashWrapper.prototype.thru; - - if (fromRight) { - funcs.reverse(); - } - while (index--) { - var func = funcs[index]; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (prereq && !wrapper && getFuncName(func) == 'wrapper') { - var wrapper = new LodashWrapper([], true); - } - } - index = wrapper ? index : length; - while (++index < length) { - func = funcs[index]; - - var funcName = getFuncName(func), - data = funcName == 'wrapper' ? getData(func) : undefined; - - if (data && isLaziable(data[0]) && - data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && - !data[4].length && data[9] == 1 - ) { - wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); - } else { - wrapper = (func.length == 1 && isLaziable(func)) - ? wrapper[funcName]() - : wrapper.thru(func); - } - } - return function() { - var args = arguments, - value = args[0]; - - if (wrapper && args.length == 1 && isArray(value)) { - return wrapper.plant(value).value(); - } - var index = 0, - result = length ? funcs[index].apply(this, args) : value; - - while (++index < length) { - result = funcs[index].call(this, result); - } - return result; - }; - }); - } - - /** - * Creates a function that wraps `func` to invoke it with optional `this` - * binding of `thisArg`, partial application, and currying. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided - * to the new function. - * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { - var isAry = bitmask & WRAP_ARY_FLAG, - isBind = bitmask & WRAP_BIND_FLAG, - isBindKey = bitmask & WRAP_BIND_KEY_FLAG, - isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), - isFlip = bitmask & WRAP_FLIP_FLAG, - Ctor = isBindKey ? undefined : createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length; - - while (index--) { - args[index] = arguments[index]; - } - if (isCurried) { - var placeholder = getHolder(wrapper), - holdersCount = countHolders(args, placeholder); - } - if (partials) { - args = composeArgs(args, partials, holders, isCurried); - } - if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight, isCurried); - } - length -= holdersCount; - if (isCurried && length < arity) { - var newHolders = replaceHolders(args, placeholder); - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, thisArg, - args, newHolders, argPos, ary, arity - length - ); - } - var thisBinding = isBind ? thisArg : this, - fn = isBindKey ? thisBinding[func] : func; - - length = args.length; - if (argPos) { - args = reorder(args, argPos); - } else if (isFlip && length > 1) { - args.reverse(); - } - if (isAry && ary < length) { - args.length = ary; - } - if (this && this !== root && this instanceof wrapper) { - fn = Ctor || createCtor(fn); - } - return fn.apply(thisBinding, args); - } - return wrapper; - } - - /** - * Creates a function like `_.invertBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} toIteratee The function to resolve iteratees. - * @returns {Function} Returns the new inverter function. - */ - function createInverter(setter, toIteratee) { - return function(object, iteratee) { - return baseInverter(object, setter, toIteratee(iteratee), {}); - }; - } - - /** - * Creates a function that performs a mathematical operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @param {number} [defaultValue] The value used for `undefined` arguments. - * @returns {Function} Returns the new mathematical operation function. - */ - function createMathOperation(operator, defaultValue) { - return function(value, other) { - var result; - if (value === undefined && other === undefined) { - return defaultValue; - } - if (value !== undefined) { - result = value; - } - if (other !== undefined) { - if (result === undefined) { - return other; - } - if (typeof value == 'string' || typeof other == 'string') { - value = baseToString(value); - other = baseToString(other); - } else { - value = baseToNumber(value); - other = baseToNumber(other); - } - result = operator(value, other); - } - return result; - }; - } - - /** - * Creates a function like `_.over`. - * - * @private - * @param {Function} arrayFunc The function to iterate over iteratees. - * @returns {Function} Returns the new over function. - */ - function createOver(arrayFunc) { - return flatRest(function(iteratees) { - iteratees = arrayMap(iteratees, baseUnary(getIteratee())); - return baseRest(function(args) { - var thisArg = this; - return arrayFunc(iteratees, function(iteratee) { - return apply(iteratee, thisArg, args); - }); - }); - }); - } - - /** - * Creates the padding for `string` based on `length`. The `chars` string - * is truncated if the number of characters exceeds `length`. - * - * @private - * @param {number} length The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padding for `string`. - */ - function createPadding(length, chars) { - chars = chars === undefined ? ' ' : baseToString(chars); - - var charsLength = chars.length; - if (charsLength < 2) { - return charsLength ? baseRepeat(chars, length) : chars; - } - var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); - return hasUnicode(chars) - ? castSlice(stringToArray(result), 0, length).join('') - : result.slice(0, length); - } - - /** - * Creates a function that wraps `func` to invoke it with the `this` binding - * of `thisArg` and `partials` prepended to the arguments it receives. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to - * the new function. - * @returns {Function} Returns the new wrapped function. - */ - function createPartial(func, bitmask, thisArg, partials) { - var isBind = bitmask & WRAP_BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var argsIndex = -1, - argsLength = arguments.length, - leftIndex = -1, - leftLength = partials.length, - args = Array(leftLength + argsLength), - fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - return apply(fn, isBind ? thisArg : this, args); - } - return wrapper; - } - - /** - * Creates a `_.range` or `_.rangeRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new range function. - */ - function createRange(fromRight) { - return function(start, end, step) { - if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { - end = step = undefined; - } - // Ensure the sign of `-0` is preserved. - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); - return baseRange(start, end, step, fromRight); - }; - } - - /** - * Creates a function that performs a relational operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @returns {Function} Returns the new relational operation function. - */ - function createRelationalOperation(operator) { - return function(value, other) { - if (!(typeof value == 'string' && typeof other == 'string')) { - value = toNumber(value); - other = toNumber(other); - } - return operator(value, other); - }; - } - - /** - * Creates a function that wraps `func` to continue currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {Function} wrapFunc The function to create the `func` wrapper. - * @param {*} placeholder The placeholder value. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { - var isCurry = bitmask & WRAP_CURRY_FLAG, - newHolders = isCurry ? holders : undefined, - newHoldersRight = isCurry ? undefined : holders, - newPartials = isCurry ? partials : undefined, - newPartialsRight = isCurry ? undefined : partials; - - bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); - bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); - - if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { - bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); - } - var newData = [ - func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, - newHoldersRight, argPos, ary, arity - ]; - - var result = wrapFunc.apply(undefined, newData); - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return setWrapToString(result, func, bitmask); - } - - /** - * Creates a function like `_.round`. - * - * @private - * @param {string} methodName The name of the `Math` method to use when rounding. - * @returns {Function} Returns the new round function. - */ - function createRound(methodName) { - var func = Math[methodName]; - return function(number, precision) { - number = toNumber(number); - precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); - if (precision) { - // Shift with exponential notation to avoid floating-point issues. - // See [MDN](https://mdn.io/round#Examples) for more details. - var pair = (toString(number) + 'e').split('e'), - value = func(pair[0] + 'e' + (+pair[1] + precision)); - - pair = (toString(value) + 'e').split('e'); - return +(pair[0] + 'e' + (+pair[1] - precision)); - } - return func(number); - }; - } - - /** - * Creates a set object of `values`. - * - * @private - * @param {Array} values The values to add to the set. - * @returns {Object} Returns the new set. - */ - var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { - return new Set(values); - }; - - /** - * Creates a `_.toPairs` or `_.toPairsIn` function. - * - * @private - * @param {Function} keysFunc The function to get the keys of a given object. - * @returns {Function} Returns the new pairs function. - */ - function createToPairs(keysFunc) { - return function(object) { - var tag = getTag(object); - if (tag == mapTag) { - return mapToArray(object); - } - if (tag == setTag) { - return setToPairs(object); - } - return baseToPairs(object, keysFunc(object)); - }; - } - - /** - * Creates a function that either curries or invokes `func` with optional - * `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` or `_.curryRight` of a bound function - * 8 - `_.curry` - * 16 - `_.curryRight` - * 32 - `_.partial` - * 64 - `_.partialRight` - * 128 - `_.rearg` - * 256 - `_.ary` - * 512 - `_.flip` - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to be partially applied. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { - var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; - if (!isBindKey && typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = partials ? partials.length : 0; - if (!length) { - bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); - partials = holders = undefined; - } - ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); - arity = arity === undefined ? arity : toInteger(arity); - length -= holders ? holders.length : 0; - - if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { - var partialsRight = partials, - holdersRight = holders; - - partials = holders = undefined; - } - var data = isBindKey ? undefined : getData(func); - - var newData = [ - func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, - argPos, ary, arity - ]; - - if (data) { - mergeData(newData, data); - } - func = newData[0]; - bitmask = newData[1]; - thisArg = newData[2]; - partials = newData[3]; - holders = newData[4]; - arity = newData[9] = newData[9] === undefined - ? (isBindKey ? 0 : func.length) - : nativeMax(newData[9] - length, 0); - - if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { - bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); - } - if (!bitmask || bitmask == WRAP_BIND_FLAG) { - var result = createBind(func, bitmask, thisArg); - } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { - result = createCurry(func, bitmask, arity); - } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { - result = createPartial(func, bitmask, thisArg, partials); - } else { - result = createHybrid.apply(undefined, newData); - } - var setter = data ? baseSetData : setData; - return setWrapToString(setter(result, newData), func, bitmask); - } - - /** - * Used by `_.defaults` to customize its `_.assignIn` use to assign properties - * of source objects to the destination object for all destination properties - * that resolve to `undefined`. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to assign. - * @param {Object} object The parent object of `objValue`. - * @returns {*} Returns the value to assign. - */ - function customDefaultsAssignIn(objValue, srcValue, key, object) { - if (objValue === undefined || - (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { - return srcValue; - } - return objValue; - } - - /** - * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source - * objects into destination objects that are passed thru. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to merge. - * @param {Object} object The parent object of `objValue`. - * @param {Object} source The parent object of `srcValue`. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - * @returns {*} Returns the value to assign. - */ - function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { - if (isObject(objValue) && isObject(srcValue)) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, objValue); - baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); - stack['delete'](srcValue); - } - return objValue; - } - - /** - * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain - * objects. - * - * @private - * @param {*} value The value to inspect. - * @param {string} key The key of the property to inspect. - * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. - */ - function customOmitClone(value) { - return isPlainObject(value) ? undefined : value; - } - - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `array` and `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, - arrLength = array.length, - othLength = other.length; - - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(array); - if (stacked && stack.get(other)) { - return stacked == other; - } - var index = -1, - result = true, - seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; - - stack.set(array, other); - stack.set(other, array); - - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, arrValue, index, other, array, stack) - : customizer(arrValue, othValue, index, array, other, stack); - } - if (compared !== undefined) { - if (compared) { - continue; - } - result = false; - break; - } - // Recursively compare arrays (susceptible to call stack limits). - if (seen) { - if (!arraySome(other, function(othValue, othIndex) { - if (!cacheHas(seen, othIndex) && - (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { - return seen.push(othIndex); - } - })) { - result = false; - break; - } - } else if (!( - arrValue === othValue || - equalFunc(arrValue, othValue, bitmask, customizer, stack) - )) { - result = false; - break; - } - } - stack['delete'](array); - stack['delete'](other); - return result; - } - - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { - switch (tag) { - case dataViewTag: - if ((object.byteLength != other.byteLength) || - (object.byteOffset != other.byteOffset)) { - return false; - } - object = object.buffer; - other = other.buffer; - - case arrayBufferTag: - if ((object.byteLength != other.byteLength) || - !equalFunc(new Uint8Array(object), new Uint8Array(other))) { - return false; - } - return true; - - case boolTag: - case dateTag: - case numberTag: - // Coerce booleans to `1` or `0` and dates to milliseconds. - // Invalid dates are coerced to `NaN`. - return eq(+object, +other); - - case errorTag: - return object.name == other.name && object.message == other.message; - - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings, primitives and objects, - // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring - // for more details. - return object == (other + ''); - - case mapTag: - var convert = mapToArray; - - case setTag: - var isPartial = bitmask & COMPARE_PARTIAL_FLAG; - convert || (convert = setToArray); - - if (object.size != other.size && !isPartial) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked) { - return stacked == other; - } - bitmask |= COMPARE_UNORDERED_FLAG; - - // Recursively compare objects (susceptible to call stack limits). - stack.set(object, other); - var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); - stack['delete'](object); - return result; - - case symbolTag: - if (symbolValueOf) { - return symbolValueOf.call(object) == symbolValueOf.call(other); - } - } - return false; - } - - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, - objProps = getAllKeys(object), - objLength = objProps.length, - othProps = getAllKeys(other), - othLength = othProps.length; - - if (objLength != othLength && !isPartial) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked && stack.get(other)) { - return stacked == other; - } - var result = true; - stack.set(object, other); - stack.set(other, object); - - var skipCtor = isPartial; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, objValue, key, other, object, stack) - : customizer(objValue, othValue, key, object, other, stack); - } - // Recursively compare objects (susceptible to call stack limits). - if (!(compared === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) - : compared - )) { - result = false; - break; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (result && !skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - result = false; - } - } - stack['delete'](object); - stack['delete'](other); - return result; - } - - /** - * A specialized version of `baseRest` which flattens the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. - */ - function flatRest(func) { - return setToString(overRest(func, undefined, flatten), func + ''); - } - - /** - * Creates an array of own enumerable property names and symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeys(object) { - return baseGetAllKeys(object, keys, getSymbols); - } - - /** - * Creates an array of own and inherited enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeysIn(object) { - return baseGetAllKeys(object, keysIn, getSymbolsIn); - } - - /** - * Gets metadata for `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {*} Returns the metadata for `func`. - */ - var getData = !metaMap ? noop : function(func) { - return metaMap.get(func); - }; - - /** - * Gets the name of `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {string} Returns the function name. - */ - function getFuncName(func) { - var result = (func.name + ''), - array = realNames[result], - length = hasOwnProperty.call(realNames, result) ? array.length : 0; - - while (length--) { - var data = array[length], - otherFunc = data.func; - if (otherFunc == null || otherFunc == func) { - return data.name; - } - } - return result; - } - - /** - * Gets the argument placeholder value for `func`. - * - * @private - * @param {Function} func The function to inspect. - * @returns {*} Returns the placeholder value. - */ - function getHolder(func) { - var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; - return object.placeholder; - } - - /** - * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, - * this function returns the custom method, otherwise it returns `baseIteratee`. - * If arguments are provided, the chosen function is invoked with them and - * its result is returned. - * - * @private - * @param {*} [value] The value to convert to an iteratee. - * @param {number} [arity] The arity of the created iteratee. - * @returns {Function} Returns the chosen function or its result. - */ - function getIteratee() { - var result = lodash.iteratee || iteratee; - result = result === iteratee ? baseIteratee : result; - return arguments.length ? result(arguments[0], arguments[1]) : result; - } - - /** - * Gets the data for `map`. - * - * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. - */ - function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; - } - - /** - * Gets the property names, values, and compare flags of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the match data of `object`. - */ - function getMatchData(object) { - var result = keys(object), - length = result.length; - - while (length--) { - var key = result[length], - value = object[key]; - - result[length] = [key, value, isStrictComparable(value)]; - } - return result; - } - - /** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ - function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; - } - - /** - * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the raw `toStringTag`. - */ - function getRawTag(value) { - var isOwn = hasOwnProperty.call(value, symToStringTag), - tag = value[symToStringTag]; - - try { - value[symToStringTag] = undefined; - var unmasked = true; - } catch (e) {} - - var result = nativeObjectToString.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag] = tag; - } else { - delete value[symToStringTag]; - } - } - return result; - } - - /** - * Creates an array of the own enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbols = !nativeGetSymbols ? stubArray : function(object) { - if (object == null) { - return []; - } - object = Object(object); - return arrayFilter(nativeGetSymbols(object), function(symbol) { - return propertyIsEnumerable.call(object, symbol); - }); - }; - - /** - * Creates an array of the own and inherited enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { - var result = []; - while (object) { - arrayPush(result, getSymbols(object)); - object = getPrototype(object); - } - return result; - }; - - /** - * Gets the `toStringTag` of `value`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - var getTag = baseGetTag; - - // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. - if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || - (Map && getTag(new Map) != mapTag) || - (Promise && getTag(Promise.resolve()) != promiseTag) || - (Set && getTag(new Set) != setTag) || - (WeakMap && getTag(new WeakMap) != weakMapTag)) { - getTag = function(value) { - var result = baseGetTag(value), - Ctor = result == objectTag ? value.constructor : undefined, - ctorString = Ctor ? toSource(Ctor) : ''; - - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: return dataViewTag; - case mapCtorString: return mapTag; - case promiseCtorString: return promiseTag; - case setCtorString: return setTag; - case weakMapCtorString: return weakMapTag; - } - } - return result; - }; - } - - /** - * Gets the view, applying any `transforms` to the `start` and `end` positions. - * - * @private - * @param {number} start The start of the view. - * @param {number} end The end of the view. - * @param {Array} transforms The transformations to apply to the view. - * @returns {Object} Returns an object containing the `start` and `end` - * positions of the view. - */ - function getView(start, end, transforms) { - var index = -1, - length = transforms.length; - - while (++index < length) { - var data = transforms[index], - size = data.size; - - switch (data.type) { - case 'drop': start += size; break; - case 'dropRight': end -= size; break; - case 'take': end = nativeMin(end, start + size); break; - case 'takeRight': start = nativeMax(start, end - size); break; - } - } - return { 'start': start, 'end': end }; - } - - /** - * Extracts wrapper details from the `source` body comment. - * - * @private - * @param {string} source The source to inspect. - * @returns {Array} Returns the wrapper details. - */ - function getWrapDetails(source) { - var match = source.match(reWrapDetails); - return match ? match[1].split(reSplitDetails) : []; - } - - /** - * Checks if `path` exists on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @param {Function} hasFunc The function to check properties. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - */ - function hasPath(object, path, hasFunc) { - path = castPath(path, object); - - var index = -1, - length = path.length, - result = false; - - while (++index < length) { - var key = toKey(path[index]); - if (!(result = object != null && hasFunc(object, key))) { - break; - } - object = object[key]; - } - if (result || ++index != length) { - return result; - } - length = object == null ? 0 : object.length; - return !!length && isLength(length) && isIndex(key, length) && - (isArray(object) || isArguments(object)); - } - - /** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ - function initCloneArray(array) { - var length = array.length, - result = new array.constructor(length); - - // Add properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } - - /** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneObject(object) { - return (typeof object.constructor == 'function' && !isPrototype(object)) - ? baseCreate(getPrototype(object)) - : {}; - } - - /** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneByTag(object, tag, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return cloneArrayBuffer(object); - - case boolTag: - case dateTag: - return new Ctor(+object); - - case dataViewTag: - return cloneDataView(object, isDeep); - - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - return cloneTypedArray(object, isDeep); - - case mapTag: - return new Ctor; - - case numberTag: - case stringTag: - return new Ctor(object); - - case regexpTag: - return cloneRegExp(object); - - case setTag: - return new Ctor; - - case symbolTag: - return cloneSymbol(object); - } - } - - /** - * Inserts wrapper `details` in a comment at the top of the `source` body. - * - * @private - * @param {string} source The source to modify. - * @returns {Array} details The details to insert. - * @returns {string} Returns the modified source. - */ - function insertWrapDetails(source, details) { - var length = details.length; - if (!length) { - return source; - } - var lastIndex = length - 1; - details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; - details = details.join(length > 2 ? ', ' : ' '); - return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); - } - - /** - * Checks if `value` is a flattenable `arguments` object or array. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ - function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); - } - - /** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ - function isIndex(value, length) { - var type = typeof value; - length = length == null ? MAX_SAFE_INTEGER : length; - - return !!length && - (type == 'number' || - (type != 'symbol' && reIsUint.test(value))) && - (value > -1 && value % 1 == 0 && value < length); - } - - /** - * Checks if the given arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, - * else `false`. - */ - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object) - ) { - return eq(object[index], value); - } - return false; - } - - /** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ - function isKey(value, object) { - if (isArray(value)) { - return false; - } - var type = typeof value; - if (type == 'number' || type == 'symbol' || type == 'boolean' || - value == null || isSymbol(value)) { - return true; - } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); - } - - /** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ - function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); - } - - /** - * Checks if `func` has a lazy counterpart. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, - * else `false`. - */ - function isLaziable(func) { - var funcName = getFuncName(func), - other = lodash[funcName]; - - if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { - return false; - } - if (func === other) { - return true; - } - var data = getData(other); - return !!data && func === data[0]; - } - - /** - * Checks if `func` has its source masked. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. - */ - function isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); - } - - /** - * Checks if `func` is capable of being masked. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `func` is maskable, else `false`. - */ - var isMaskable = coreJsData ? isFunction : stubFalse; - - /** - * Checks if `value` is likely a prototype object. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ - function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - - return value === proto; - } - - /** - * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` if suitable for strict - * equality comparisons, else `false`. - */ - function isStrictComparable(value) { - return value === value && !isObject(value); - } - - /** - * A specialized version of `matchesProperty` for source values suitable - * for strict equality comparisons, i.e. `===`. - * - * @private - * @param {string} key The key of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function matchesStrictComparable(key, srcValue) { - return function(object) { - if (object == null) { - return false; - } - return object[key] === srcValue && - (srcValue !== undefined || (key in Object(object))); - }; - } - - /** - * A specialized version of `_.memoize` which clears the memoized function's - * cache when it exceeds `MAX_MEMOIZE_SIZE`. - * - * @private - * @param {Function} func The function to have its output memoized. - * @returns {Function} Returns the new memoized function. - */ - function memoizeCapped(func) { - var result = memoize(func, function(key) { - if (cache.size === MAX_MEMOIZE_SIZE) { - cache.clear(); - } - return key; - }); - - var cache = result.cache; - return result; - } - - /** - * Merges the function metadata of `source` into `data`. - * - * Merging metadata reduces the number of wrappers used to invoke a function. - * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and - * `_.rearg` modify function arguments, making the order in which they are - * executed important, preventing the merging of metadata. However, we make - * an exception for a safe combined case where curried functions have `_.ary` - * and or `_.rearg` applied. - * - * @private - * @param {Array} data The destination metadata. - * @param {Array} source The source metadata. - * @returns {Array} Returns `data`. - */ - function mergeData(data, source) { - var bitmask = data[1], - srcBitmask = source[1], - newBitmask = bitmask | srcBitmask, - isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); - - var isCombo = - ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || - ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || - ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); - - // Exit early if metadata can't be merged. - if (!(isCommon || isCombo)) { - return data; - } - // Use source `thisArg` if available. - if (srcBitmask & WRAP_BIND_FLAG) { - data[2] = source[2]; - // Set when currying a bound function. - newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; - } - // Compose partial arguments. - var value = source[3]; - if (value) { - var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : value; - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; - } - // Compose partial right arguments. - value = source[5]; - if (value) { - partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; - } - // Use source `argPos` if available. - value = source[7]; - if (value) { - data[7] = value; - } - // Use source `ary` if it's smaller. - if (srcBitmask & WRAP_ARY_FLAG) { - data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); - } - // Use source `arity` if one is not provided. - if (data[9] == null) { - data[9] = source[9]; - } - // Use source `func` and merge bitmasks. - data[0] = source[0]; - data[1] = newBitmask; - - return data; - } - - /** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); - } - } - return result; - } - - /** - * Converts `value` to a string using `Object.prototype.toString`. - * - * @private - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - */ - function objectToString(value) { - return nativeObjectToString.call(value); - } - - /** - * A specialized version of `baseRest` which transforms the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @param {Function} transform The rest array transform. - * @returns {Function} Returns the new function. - */ - function overRest(func, start, transform) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); - - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = transform(array); - return apply(func, this, otherArgs); - }; - } - - /** - * Gets the parent value at `path` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path to get the parent value of. - * @returns {*} Returns the parent value. - */ - function parent(object, path) { - return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); - } - - /** - * Reorder `array` according to the specified indexes where the element at - * the first index is assigned as the first element, the element at - * the second index is assigned as the second element, and so on. - * - * @private - * @param {Array} array The array to reorder. - * @param {Array} indexes The arranged array indexes. - * @returns {Array} Returns `array`. - */ - function reorder(array, indexes) { - var arrLength = array.length, - length = nativeMin(indexes.length, arrLength), - oldArray = copyArray(array); - - while (length--) { - var index = indexes[length]; - array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; - } - return array; - } - - /** - * Sets metadata for `func`. - * - * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity - * function to avoid garbage collection pauses in V8. See - * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) - * for more details. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var setData = shortOut(baseSetData); - - /** - * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @returns {number|Object} Returns the timer id or timeout object. - */ - var setTimeout = ctxSetTimeout || function(func, wait) { - return root.setTimeout(func, wait); - }; - - /** - * Sets the `toString` method of `func` to return `string`. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ - var setToString = shortOut(baseSetToString); - - /** - * Sets the `toString` method of `wrapper` to mimic the source of `reference` - * with wrapper details in a comment at the top of the source body. - * - * @private - * @param {Function} wrapper The function to modify. - * @param {Function} reference The reference function. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Function} Returns `wrapper`. - */ - function setWrapToString(wrapper, reference, bitmask) { - var source = (reference + ''); - return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); - } - - /** - * Creates a function that'll short out and invoke `identity` instead - * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` - * milliseconds. - * - * @private - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new shortable function. - */ - function shortOut(func) { - var count = 0, - lastCalled = 0; - - return function() { - var stamp = nativeNow(), - remaining = HOT_SPAN - (stamp - lastCalled); - - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return arguments[0]; - } - } else { - count = 0; - } - return func.apply(undefined, arguments); - }; - } - - /** - * A specialized version of `_.shuffle` which mutates and sets the size of `array`. - * - * @private - * @param {Array} array The array to shuffle. - * @param {number} [size=array.length] The size of `array`. - * @returns {Array} Returns `array`. - */ - function shuffleSelf(array, size) { - var index = -1, - length = array.length, - lastIndex = length - 1; - - size = size === undefined ? length : size; - while (++index < size) { - var rand = baseRandom(index, lastIndex), - value = array[rand]; - - array[rand] = array[index]; - array[index] = value; - } - array.length = size; - return array; - } - - /** - * Converts `string` to a property path array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the property path array. - */ - var stringToPath = memoizeCapped(function(string) { - var result = []; - if (string.charCodeAt(0) === 46 /* . */) { - result.push(''); - } - string.replace(rePropName, function(match, number, quote, subString) { - result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; - }); - - /** - * Converts `value` to a string key if it's not a string or symbol. - * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. - */ - function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to convert. - * @returns {string} Returns the source code. - */ - function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; - } - - /** - * Updates wrapper `details` based on `bitmask` flags. - * - * @private - * @returns {Array} details The details to modify. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Array} Returns `details`. - */ - function updateWrapDetails(details, bitmask) { - arrayEach(wrapFlags, function(pair) { - var value = '_.' + pair[0]; - if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { - details.push(value); - } - }); - return details.sort(); - } - - /** - * Creates a clone of `wrapper`. - * - * @private - * @param {Object} wrapper The wrapper to clone. - * @returns {Object} Returns the cloned wrapper. - */ - function wrapperClone(wrapper) { - if (wrapper instanceof LazyWrapper) { - return wrapper.clone(); - } - var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); - result.__actions__ = copyArray(wrapper.__actions__); - result.__index__ = wrapper.__index__; - result.__values__ = wrapper.__values__; - return result; - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of elements split into groups the length of `size`. - * If `array` can't be split evenly, the final chunk will be the remaining - * elements. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to process. - * @param {number} [size=1] The length of each chunk - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the new array of chunks. - * @example - * - * _.chunk(['a', 'b', 'c', 'd'], 2); - * // => [['a', 'b'], ['c', 'd']] - * - * _.chunk(['a', 'b', 'c', 'd'], 3); - * // => [['a', 'b', 'c'], ['d']] - */ - function chunk(array, size, guard) { - if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { - size = 1; - } else { - size = nativeMax(toInteger(size), 0); - } - var length = array == null ? 0 : array.length; - if (!length || size < 1) { - return []; - } - var index = 0, - resIndex = 0, - result = Array(nativeCeil(length / size)); - - while (index < length) { - result[resIndex++] = baseSlice(array, index, (index += size)); - } - return result; - } - - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * Creates a new array concatenating `array` with any additional arrays - * and/or values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to concatenate. - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var other = _.concat(array, 2, [3], [[4]]); - * - * console.log(other); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - function concat() { - var length = arguments.length; - if (!length) { - return []; - } - var args = Array(length - 1), - array = arguments[0], - index = length; - - while (index--) { - args[index - 1] = arguments[index]; - } - return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); - } - - /** - * Creates an array of `array` values not included in the other given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * **Note:** Unlike `_.pullAll`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.without, _.xor - * @example - * - * _.difference([2, 1], [2, 3]); - * // => [1] - */ - var difference = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : []; - }); - - /** - * This method is like `_.difference` except that it accepts `iteratee` which - * is invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. The order and references of result values are - * determined by the first array. The iteratee is invoked with one argument: - * (value). - * - * **Note:** Unlike `_.pullAllBy`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [1.2] - * - * // The `_.property` iteratee shorthand. - * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); - * // => [{ 'x': 2 }] - */ - var differenceBy = baseRest(function(array, values) { - var iteratee = last(values); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) - : []; - }); - - /** - * This method is like `_.difference` except that it accepts `comparator` - * which is invoked to compare elements of `array` to `values`. The order and - * references of result values are determined by the first array. The comparator - * is invoked with two arguments: (arrVal, othVal). - * - * **Note:** Unlike `_.pullAllWith`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * - * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); - * // => [{ 'x': 2, 'y': 1 }] - */ - var differenceWith = baseRest(function(array, values) { - var comparator = last(values); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) - : []; - }); - - /** - * Creates a slice of `array` with `n` elements dropped from the beginning. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.drop([1, 2, 3]); - * // => [2, 3] - * - * _.drop([1, 2, 3], 2); - * // => [3] - * - * _.drop([1, 2, 3], 5); - * // => [] - * - * _.drop([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function drop(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, n < 0 ? 0 : n, length); - } - - /** - * Creates a slice of `array` with `n` elements dropped from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRight([1, 2, 3]); - * // => [1, 2] - * - * _.dropRight([1, 2, 3], 2); - * // => [1] - * - * _.dropRight([1, 2, 3], 5); - * // => [] - * - * _.dropRight([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function dropRight(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` excluding elements dropped from the end. - * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.dropRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney'] - * - * // The `_.matches` iteratee shorthand. - * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['barney', 'fred'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropRightWhile(users, ['active', false]); - * // => objects for ['barney'] - * - * // The `_.property` iteratee shorthand. - * _.dropRightWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] - */ - function dropRightWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true, true) - : []; - } - - /** - * Creates a slice of `array` excluding elements dropped from the beginning. - * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.dropWhile(users, function(o) { return !o.active; }); - * // => objects for ['pebbles'] - * - * // The `_.matches` iteratee shorthand. - * _.dropWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropWhile(users, ['active', false]); - * // => objects for ['pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.dropWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] - */ - function dropWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true) - : []; - } - - /** - * Fills elements of `array` with `value` from `start` up to, but not - * including, `end`. - * - * **Note:** This method mutates `array`. - * - * @static - * @memberOf _ - * @since 3.2.0 - * @category Array - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.fill(array, 'a'); - * console.log(array); - * // => ['a', 'a', 'a'] - * - * _.fill(Array(3), 2); - * // => [2, 2, 2] - * - * _.fill([4, 6, 8, 10], '*', 1, 3); - * // => [4, '*', '*', 10] - */ - function fill(array, value, start, end) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { - start = 0; - end = length; - } - return baseFill(array, value, start, end); - } - - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(o) { return o.user == 'barney'; }); - * // => 0 - * - * // The `_.matches` iteratee shorthand. - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findIndex(users, ['active', false]); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.findIndex(users, 'active'); - * // => 2 - */ - function findIndex(array, predicate, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = fromIndex == null ? 0 : toInteger(fromIndex); - if (index < 0) { - index = nativeMax(length + index, 0); - } - return baseFindIndex(array, getIteratee(predicate, 3), index); - } - - /** - * This method is like `_.findIndex` except that it iterates over elements - * of `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); - * // => 2 - * - * // The `_.matches` iteratee shorthand. - * _.findLastIndex(users, { 'user': 'barney', 'active': true }); - * // => 0 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastIndex(users, ['active', false]); - * // => 2 - * - * // The `_.property` iteratee shorthand. - * _.findLastIndex(users, 'active'); - * // => 0 - */ - function findLastIndex(array, predicate, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = length - 1; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = fromIndex < 0 - ? nativeMax(length + index, 0) - : nativeMin(index, length - 1); - } - return baseFindIndex(array, getIteratee(predicate, 3), index, true); - } - - /** - * Flattens `array` a single level deep. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] - */ - function flatten(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, 1) : []; - } - - /** - * Recursively flattens `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, [3, [4]], 5]]); - * // => [1, 2, 3, 4, 5] - */ - function flattenDeep(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, INFINITY) : []; - } - - /** - * Recursively flatten `array` up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Array - * @param {Array} array The array to flatten. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * var array = [1, [2, [3, [4]], 5]]; - * - * _.flattenDepth(array, 1); - * // => [1, 2, [3, [4]], 5] - * - * _.flattenDepth(array, 2); - * // => [1, 2, 3, [4], 5] - */ - function flattenDepth(array, depth) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(array, depth); - } - - /** - * The inverse of `_.toPairs`; this method returns an object composed - * from key-value `pairs`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} pairs The key-value pairs. - * @returns {Object} Returns the new object. - * @example - * - * _.fromPairs([['a', 1], ['b', 2]]); - * // => { 'a': 1, 'b': 2 } - */ - function fromPairs(pairs) { - var index = -1, - length = pairs == null ? 0 : pairs.length, - result = {}; - - while (++index < length) { - var pair = pairs[index]; - result[pair[0]] = pair[1]; - } - return result; - } - - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias first - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.head([1, 2, 3]); - * // => 1 - * - * _.head([]); - * // => undefined - */ - function head(array) { - return (array && array.length) ? array[0] : undefined; - } - - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the - * offset from the end of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // Search from the `fromIndex`. - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - */ - function indexOf(array, value, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = fromIndex == null ? 0 : toInteger(fromIndex); - if (index < 0) { - index = nativeMax(length + index, 0); - } - return baseIndexOf(array, value, index); - } - - /** - * Gets all but the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - */ - function initial(array) { - var length = array == null ? 0 : array.length; - return length ? baseSlice(array, 0, -1) : []; - } - - /** - * Creates an array of unique values that are included in all given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersection([2, 1], [2, 3]); - * // => [2] - */ - var intersection = baseRest(function(arrays) { - var mapped = arrayMap(arrays, castArrayLikeObject); - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped) - : []; - }); - - /** - * This method is like `_.intersection` except that it accepts `iteratee` - * which is invoked for each element of each `arrays` to generate the criterion - * by which they're compared. The order and references of result values are - * determined by the first array. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [2.1] - * - * // The `_.property` iteratee shorthand. - * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }] - */ - var intersectionBy = baseRest(function(arrays) { - var iteratee = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); - - if (iteratee === last(mapped)) { - iteratee = undefined; - } else { - mapped.pop(); - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, getIteratee(iteratee, 2)) - : []; - }); - - /** - * This method is like `_.intersection` except that it accepts `comparator` - * which is invoked to compare elements of `arrays`. The order and references - * of result values are determined by the first array. The comparator is - * invoked with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.intersectionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }] - */ - var intersectionWith = baseRest(function(arrays) { - var comparator = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); - - comparator = typeof comparator == 'function' ? comparator : undefined; - if (comparator) { - mapped.pop(); - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, undefined, comparator) - : []; - }); - - /** - * Converts all elements in `array` into a string separated by `separator`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to convert. - * @param {string} [separator=','] The element separator. - * @returns {string} Returns the joined string. - * @example - * - * _.join(['a', 'b', 'c'], '~'); - * // => 'a~b~c' - */ - function join(array, separator) { - return array == null ? '' : nativeJoin.call(array, separator); - } - - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array == null ? 0 : array.length; - return length ? array[length - 1] : undefined; - } - - /** - * This method is like `_.indexOf` except that it iterates over elements of - * `array` from right to left. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.lastIndexOf([1, 2, 1, 2], 2); - * // => 3 - * - * // Search from the `fromIndex`. - * _.lastIndexOf([1, 2, 1, 2], 2, 2); - * // => 1 - */ - function lastIndexOf(array, value, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = length; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); - } - return value === value - ? strictLastIndexOf(array, value, index) - : baseFindIndex(array, baseIsNaN, index, true); - } - - /** - * Gets the element at index `n` of `array`. If `n` is negative, the nth - * element from the end is returned. - * - * @static - * @memberOf _ - * @since 4.11.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=0] The index of the element to return. - * @returns {*} Returns the nth element of `array`. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * - * _.nth(array, 1); - * // => 'b' - * - * _.nth(array, -2); - * // => 'c'; - */ - function nth(array, n) { - return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; - } - - /** - * Removes all given values from `array` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` - * to remove elements from an array by predicate. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {...*} [values] The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pull(array, 'a', 'c'); - * console.log(array); - * // => ['b', 'b'] - */ - var pull = baseRest(pullAll); - - /** - * This method is like `_.pull` except that it accepts an array of values to remove. - * - * **Note:** Unlike `_.difference`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pullAll(array, ['a', 'c']); - * console.log(array); - * // => ['b', 'b'] - */ - function pullAll(array, values) { - return (array && array.length && values && values.length) - ? basePullAll(array, values) - : array; - } - - /** - * This method is like `_.pullAll` except that it accepts `iteratee` which is - * invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. The iteratee is invoked with one argument: (value). - * - * **Note:** Unlike `_.differenceBy`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; - * - * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); - * console.log(array); - * // => [{ 'x': 2 }] - */ - function pullAllBy(array, values, iteratee) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, getIteratee(iteratee, 2)) - : array; - } - - /** - * This method is like `_.pullAll` except that it accepts `comparator` which - * is invoked to compare elements of `array` to `values`. The comparator is - * invoked with two arguments: (arrVal, othVal). - * - * **Note:** Unlike `_.differenceWith`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; - * - * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); - * console.log(array); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] - */ - function pullAllWith(array, values, comparator) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, undefined, comparator) - : array; - } - - /** - * Removes elements from `array` corresponding to `indexes` and returns an - * array of removed elements. - * - * **Note:** Unlike `_.at`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {...(number|number[])} [indexes] The indexes of elements to remove. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * var pulled = _.pullAt(array, [1, 3]); - * - * console.log(array); - * // => ['a', 'c'] - * - * console.log(pulled); - * // => ['b', 'd'] - */ - var pullAt = flatRest(function(array, indexes) { - var length = array == null ? 0 : array.length, - result = baseAt(array, indexes); - - basePullAt(array, arrayMap(indexes, function(index) { - return isIndex(index, length) ? +index : index; - }).sort(compareAscending)); - - return result; - }); - - /** - * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is invoked - * with three arguments: (value, index, array). - * - * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` - * to pull elements from an array by value. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [1, 2, 3, 4]; - * var evens = _.remove(array, function(n) { - * return n % 2 == 0; - * }); - * - * console.log(array); - * // => [1, 3] - * - * console.log(evens); - * // => [2, 4] - */ - function remove(array, predicate) { - var result = []; - if (!(array && array.length)) { - return result; - } - var index = -1, - indexes = [], - length = array.length; - - predicate = getIteratee(predicate, 3); - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result.push(value); - indexes.push(index); - } - } - basePullAt(array, indexes); - return result; - } - - /** - * Reverses `array` so that the first element becomes the last, the second - * element becomes the second to last, and so on. - * - * **Note:** This method mutates `array` and is based on - * [`Array#reverse`](https://mdn.io/Array/reverse). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.reverse(array); - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function reverse(array) { - return array == null ? array : nativeReverse.call(array); - } - - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of - * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are - * returned. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - else { - start = start == null ? 0 : toInteger(start); - end = end === undefined ? length : toInteger(end); - } - return baseSlice(array, start, end); - } - - /** - * Uses a binary search to determine the lowest index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedIndex([30, 50], 40); - * // => 1 - */ - function sortedIndex(array, value) { - return baseSortedIndex(array, value); - } - - /** - * This method is like `_.sortedIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); - * // => 0 - */ - function sortedIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); - } - - /** - * This method is like `_.indexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedIndexOf([4, 5, 5, 5, 6], 5); - * // => 1 - */ - function sortedIndexOf(array, value) { - var length = array == null ? 0 : array.length; - if (length) { - var index = baseSortedIndex(array, value); - if (index < length && eq(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * This method is like `_.sortedIndex` except that it returns the highest - * index at which `value` should be inserted into `array` in order to - * maintain its sort order. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedLastIndex([4, 5, 5, 5, 6], 5); - * // => 4 - */ - function sortedLastIndex(array, value) { - return baseSortedIndex(array, value, true); - } - - /** - * This method is like `_.sortedLastIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 1 - * - * // The `_.property` iteratee shorthand. - * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); - * // => 1 - */ - function sortedLastIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); - } - - /** - * This method is like `_.lastIndexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); - * // => 3 - */ - function sortedLastIndexOf(array, value) { - var length = array == null ? 0 : array.length; - if (length) { - var index = baseSortedIndex(array, value, true) - 1; - if (eq(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * This method is like `_.uniq` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniq([1, 1, 2]); - * // => [1, 2] - */ - function sortedUniq(array) { - return (array && array.length) - ? baseSortedUniq(array) - : []; - } - - /** - * This method is like `_.uniqBy` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); - * // => [1.1, 2.3] - */ - function sortedUniqBy(array, iteratee) { - return (array && array.length) - ? baseSortedUniq(array, getIteratee(iteratee, 2)) - : []; - } - - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.tail([1, 2, 3]); - * // => [2, 3] - */ - function tail(array) { - var length = array == null ? 0 : array.length; - return length ? baseSlice(array, 1, length) : []; - } - - /** - * Creates a slice of `array` with `n` elements taken from the beginning. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.take([1, 2, 3]); - * // => [1] - * - * _.take([1, 2, 3], 2); - * // => [1, 2] - * - * _.take([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.take([1, 2, 3], 0); - * // => [] - */ - function take(array, n, guard) { - if (!(array && array.length)) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` with `n` elements taken from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRight([1, 2, 3]); - * // => [3] - * - * _.takeRight([1, 2, 3], 2); - * // => [2, 3] - * - * _.takeRight([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.takeRight([1, 2, 3], 0); - * // => [] - */ - function takeRight(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, n < 0 ? 0 : n, length); - } - - /** - * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.takeRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.matches` iteratee shorthand. - * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['pebbles'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeRightWhile(users, ['active', false]); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.takeRightWhile(users, 'active'); - * // => [] - */ - function takeRightWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), false, true) - : []; - } - - /** - * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.takeWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney', 'fred'] - * - * // The `_.matches` iteratee shorthand. - * _.takeWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeWhile(users, ['active', false]); - * // => objects for ['barney', 'fred'] - * - * // The `_.property` iteratee shorthand. - * _.takeWhile(users, 'active'); - * // => [] - */ - function takeWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3)) - : []; - } - - /** - * Creates an array of unique values, in order, from all given arrays using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.union([2], [1, 2]); - * // => [2, 1] - */ - var union = baseRest(function(arrays) { - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); - }); - - /** - * This method is like `_.union` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which uniqueness is computed. Result values are chosen from the first - * array in which the value occurs. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.unionBy([2.1], [1.2, 2.3], Math.floor); - * // => [2.1, 1.2] - * - * // The `_.property` iteratee shorthand. - * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - var unionBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); - }); - - /** - * This method is like `_.union` except that it accepts `comparator` which - * is invoked to compare elements of `arrays`. Result values are chosen from - * the first array in which the value occurs. The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.unionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var unionWith = baseRest(function(arrays) { - var comparator = last(arrays); - comparator = typeof comparator == 'function' ? comparator : undefined; - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); - }); - - /** - * Creates a duplicate-free version of an array, using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons, in which only the first occurrence of each element - * is kept. The order of result values is determined by the order they occur - * in the array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniq([2, 1, 2]); - * // => [2, 1] - */ - function uniq(array) { - return (array && array.length) ? baseUniq(array) : []; - } - - /** - * This method is like `_.uniq` except that it accepts `iteratee` which is - * invoked for each element in `array` to generate the criterion by which - * uniqueness is computed. The order of result values is determined by the - * order they occur in the array. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniqBy([2.1, 1.2, 2.3], Math.floor); - * // => [2.1, 1.2] - * - * // The `_.property` iteratee shorthand. - * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniqBy(array, iteratee) { - return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; - } - - /** - * This method is like `_.uniq` except that it accepts `comparator` which - * is invoked to compare elements of `array`. The order of result values is - * determined by the order they occur in the array.The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.uniqWith(objects, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] - */ - function uniqWith(array, comparator) { - comparator = typeof comparator == 'function' ? comparator : undefined; - return (array && array.length) ? baseUniq(array, undefined, comparator) : []; - } - - /** - * This method is like `_.zip` except that it accepts an array of grouped - * elements and creates an array regrouping the elements to their pre-zip - * configuration. - * - * @static - * @memberOf _ - * @since 1.2.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - * - * _.unzip(zipped); - * // => [['a', 'b'], [1, 2], [true, false]] - */ - function unzip(array) { - if (!(array && array.length)) { - return []; - } - var length = 0; - array = arrayFilter(array, function(group) { - if (isArrayLikeObject(group)) { - length = nativeMax(group.length, length); - return true; - } - }); - return baseTimes(length, function(index) { - return arrayMap(array, baseProperty(index)); - }); - } - - /** - * This method is like `_.unzip` except that it accepts `iteratee` to specify - * how regrouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee=_.identity] The function to combine - * regrouped values. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip([1, 2], [10, 20], [100, 200]); - * // => [[1, 10, 100], [2, 20, 200]] - * - * _.unzipWith(zipped, _.add); - * // => [3, 30, 300] - */ - function unzipWith(array, iteratee) { - if (!(array && array.length)) { - return []; - } - var result = unzip(array); - if (iteratee == null) { - return result; - } - return arrayMap(result, function(group) { - return apply(iteratee, undefined, group); - }); - } - - /** - * Creates an array excluding all given values using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.pull`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...*} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.xor - * @example - * - * _.without([2, 1, 2, 3], 1, 2); - * // => [3] - */ - var without = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, values) - : []; - }); - - /** - * Creates an array of unique values that is the - * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) - * of the given arrays. The order of result values is determined by the order - * they occur in the arrays. - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.without - * @example - * - * _.xor([2, 1], [2, 3]); - * // => [1, 3] - */ - var xor = baseRest(function(arrays) { - return baseXor(arrayFilter(arrays, isArrayLikeObject)); - }); - - /** - * This method is like `_.xor` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which by which they're compared. The order of result values is determined - * by the order they occur in the arrays. The iteratee is invoked with one - * argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [1.2, 3.4] - * - * // The `_.property` iteratee shorthand. - * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 2 }] - */ - var xorBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); - }); - - /** - * This method is like `_.xor` except that it accepts `comparator` which is - * invoked to compare elements of `arrays`. The order of result values is - * determined by the order they occur in the arrays. The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.xorWith(objects, others, _.isEqual); - * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var xorWith = baseRest(function(arrays) { - var comparator = last(arrays); - comparator = typeof comparator == 'function' ? comparator : undefined; - return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); - }); - - /** - * Creates an array of grouped elements, the first of which contains the - * first elements of the given arrays, the second of which contains the - * second elements of the given arrays, and so on. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - */ - var zip = baseRest(unzip); - - /** - * This method is like `_.fromPairs` except that it accepts two arrays, - * one of property identifiers and one of corresponding values. - * - * @static - * @memberOf _ - * @since 0.4.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject(['a', 'b'], [1, 2]); - * // => { 'a': 1, 'b': 2 } - */ - function zipObject(props, values) { - return baseZipObject(props || [], values || [], assignValue); - } - - /** - * This method is like `_.zipObject` except that it supports property paths. - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); - * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } - */ - function zipObjectDeep(props, values) { - return baseZipObject(props || [], values || [], baseSet); - } - - /** - * This method is like `_.zip` except that it accepts `iteratee` to specify - * how grouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee=_.identity] The function to combine - * grouped values. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { - * return a + b + c; - * }); - * // => [111, 222] - */ - var zipWith = baseRest(function(arrays) { - var length = arrays.length, - iteratee = length > 1 ? arrays[length - 1] : undefined; - - iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; - return unzipWith(arrays, iteratee); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` wrapper instance that wraps `value` with explicit method - * chain sequences enabled. The result of such sequences must be unwrapped - * with `_#value`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Seq - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _ - * .chain(users) - * .sortBy('age') - * .map(function(o) { - * return o.user + ' is ' + o.age; - * }) - * .head() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } - - /** - * This method invokes `interceptor` and returns `value`. The interceptor - * is invoked with one argument; (value). The purpose of this method is to - * "tap into" a method chain sequence in order to modify intermediate results. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * // Mutate input array. - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor) { - interceptor(value); - return value; - } - - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * The purpose of this method is to "pass thru" values replacing intermediate - * results in a method chain sequence. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor) { - return interceptor(value); - } - - /** - * This method is the wrapper version of `_.at`. - * - * @name at - * @memberOf _ - * @since 1.0.0 - * @category Seq - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _(object).at(['a[0].b.c', 'a[1]']).value(); - * // => [3, 4] - */ - var wrapperAt = flatRest(function(paths) { - var length = paths.length, - start = length ? paths[0] : 0, - value = this.__wrapped__, - interceptor = function(object) { return baseAt(object, paths); }; - - if (length > 1 || this.__actions__.length || - !(value instanceof LazyWrapper) || !isIndex(start)) { - return this.thru(interceptor); - } - value = value.slice(start, +start + (length ? 1 : 0)); - value.__actions__.push({ - 'func': thru, - 'args': [interceptor], - 'thisArg': undefined - }); - return new LodashWrapper(value, this.__chain__).thru(function(array) { - if (length && !array.length) { - array.push(undefined); - } - return array; - }); - }); - - /** - * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. - * - * @name chain - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // A sequence without explicit chaining. - * _(users).head(); - * // => { 'user': 'barney', 'age': 36 } - * - * // A sequence with explicit chaining. - * _(users) - * .chain() - * .head() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } - - /** - * Executes the chain sequence and returns the wrapped result. - * - * @name commit - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).push(3); - * - * console.log(array); - * // => [1, 2] - * - * wrapped = wrapped.commit(); - * console.log(array); - * // => [1, 2, 3] - * - * wrapped.last(); - * // => 3 - * - * console.log(array); - * // => [1, 2, 3] - */ - function wrapperCommit() { - return new LodashWrapper(this.value(), this.__chain__); - } - - /** - * Gets the next value on a wrapped object following the - * [iterator protocol](https://mdn.io/iteration_protocols#iterator). - * - * @name next - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the next iterator value. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped.next(); - * // => { 'done': false, 'value': 1 } - * - * wrapped.next(); - * // => { 'done': false, 'value': 2 } - * - * wrapped.next(); - * // => { 'done': true, 'value': undefined } - */ - function wrapperNext() { - if (this.__values__ === undefined) { - this.__values__ = toArray(this.value()); - } - var done = this.__index__ >= this.__values__.length, - value = done ? undefined : this.__values__[this.__index__++]; - - return { 'done': done, 'value': value }; - } - - /** - * Enables the wrapper to be iterable. - * - * @name Symbol.iterator - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the wrapper object. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped[Symbol.iterator]() === wrapped; - * // => true - * - * Array.from(wrapped); - * // => [1, 2] - */ - function wrapperToIterator() { - return this; - } - - /** - * Creates a clone of the chain sequence planting `value` as the wrapped value. - * - * @name plant - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @param {*} value The value to plant. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2]).map(square); - * var other = wrapped.plant([3, 4]); - * - * other.value(); - * // => [9, 16] - * - * wrapped.value(); - * // => [1, 4] - */ - function wrapperPlant(value) { - var result, - parent = this; - - while (parent instanceof baseLodash) { - var clone = wrapperClone(parent); - clone.__index__ = 0; - clone.__values__ = undefined; - if (result) { - previous.__wrapped__ = clone; - } else { - result = clone; - } - var previous = clone; - parent = parent.__wrapped__; - } - previous.__wrapped__ = value; - return result; - } - - /** - * This method is the wrapper version of `_.reverse`. - * - * **Note:** This method mutates the wrapped array. - * - * @name reverse - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2, 3]; - * - * _(array).reverse().value() - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function wrapperReverse() { - var value = this.__wrapped__; - if (value instanceof LazyWrapper) { - var wrapped = value; - if (this.__actions__.length) { - wrapped = new LazyWrapper(this); - } - wrapped = wrapped.reverse(); - wrapped.__actions__.push({ - 'func': thru, - 'args': [reverse], - 'thisArg': undefined - }); - return new LodashWrapper(wrapped, this.__chain__); - } - return this.thru(reverse); - } - - /** - * Executes the chain sequence to resolve the unwrapped value. - * - * @name value - * @memberOf _ - * @since 0.1.0 - * @alias toJSON, valueOf - * @category Seq - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the number of times the key was returned by `iteratee`. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.countBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': 1, '6': 2 } - * - * // The `_.property` iteratee shorthand. - * _.countBy(['one', 'two', 'three'], 'length'); - * // => { '3': 2, '5': 1 } - */ - var countBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - ++result[key]; - } else { - baseAssignValue(result, key, 1); - } - }); - - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * Iteration is stopped once `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * **Note:** This method returns `true` for - * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because - * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of - * elements of empty collections. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.every(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, guard) { - var func = isArray(collection) ? arrayEvery : baseEvery; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * **Note:** Unlike `_.remove`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.reject - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.filter(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.filter(users, { 'age': 36, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.filter(users, 'active'); - * // => objects for ['barney'] - */ - function filter(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.find(users, function(o) { return o.age < 40; }); - * // => object for 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.find(users, { 'age': 1, 'active': true }); - * // => object for 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.find(users, ['active', false]); - * // => object for 'fred' - * - * // The `_.property` iteratee shorthand. - * _.find(users, 'active'); - * // => object for 'barney' - */ - var find = createFind(findIndex); - - /** - * This method is like `_.find` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=collection.length-1] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * _.findLast([1, 2, 3, 4], function(n) { - * return n % 2 == 1; - * }); - * // => 3 - */ - var findLast = createFind(findLastIndex); - - /** - * Creates a flattened array of values by running each element in `collection` - * thru `iteratee` and flattening the mapped results. The iteratee is invoked - * with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [n, n]; - * } - * - * _.flatMap([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMap(collection, iteratee) { - return baseFlatten(map(collection, iteratee), 1); - } - - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDeep([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMapDeep(collection, iteratee) { - return baseFlatten(map(collection, iteratee), INFINITY); - } - - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDepth([1, 2], duplicate, 2); - * // => [[1, 1], [2, 2]] - */ - function flatMapDepth(collection, iteratee, depth) { - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(map(collection, iteratee), depth); - } - - /** - * Iterates over elements of `collection` and invokes `iteratee` for each element. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" - * property are iterated like arrays. To avoid this behavior use `_.forIn` - * or `_.forOwn` for object iteration. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias each - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEachRight - * @example - * - * _.forEach([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `1` then `2`. - * - * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forEach(collection, iteratee) { - var func = isArray(collection) ? arrayEach : baseEach; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.forEach` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @alias eachRight - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEach - * @example - * - * _.forEachRight([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `2` then `1`. - */ - function forEachRight(collection, iteratee) { - var func = isArray(collection) ? arrayEachRight : baseEachRight; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The order of grouped values - * is determined by the order they occur in `collection`. The corresponding - * value of each key is an array of elements responsible for generating the - * key. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': [4.2], '6': [6.1, 6.3] } - * - * // The `_.property` iteratee shorthand. - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - result[key].push(value); - } else { - baseAssignValue(result, key, [value]); - } - }); - - /** - * Checks if `value` is in `collection`. If `collection` is a string, it's - * checked for a substring of `value`, otherwise - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * is used for equality comparisons. If `fromIndex` is negative, it's used as - * the offset from the end of `collection`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {boolean} Returns `true` if `value` is found, else `false`. - * @example - * - * _.includes([1, 2, 3], 1); - * // => true - * - * _.includes([1, 2, 3], 1, 2); - * // => false - * - * _.includes({ 'a': 1, 'b': 2 }, 1); - * // => true - * - * _.includes('abcd', 'bc'); - * // => true - */ - function includes(collection, value, fromIndex, guard) { - collection = isArrayLike(collection) ? collection : values(collection); - fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; - - var length = collection.length; - if (fromIndex < 0) { - fromIndex = nativeMax(length + fromIndex, 0); - } - return isString(collection) - ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) - : (!!length && baseIndexOf(collection, value, fromIndex) > -1); - } - - /** - * Invokes the method at `path` of each element in `collection`, returning - * an array of the results of each invoked method. Any additional arguments - * are provided to each invoked method. If `path` is a function, it's invoked - * for, and `this` bound to, each element in `collection`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or - * the function invoked per iteration. - * @param {...*} [args] The arguments to invoke each method with. - * @returns {Array} Returns the array of results. - * @example - * - * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); - * // => [[1, 5, 7], [1, 2, 3]] - * - * _.invokeMap([123, 456], String.prototype.split, ''); - * // => [['1', '2', '3'], ['4', '5', '6']] - */ - var invokeMap = baseRest(function(collection, path, args) { - var index = -1, - isFunc = typeof path == 'function', - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value) { - result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); - }); - return result; - }); - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the last element responsible for generating the key. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * var array = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; - * - * _.keyBy(array, function(o) { - * return String.fromCharCode(o.code); - * }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.keyBy(array, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - */ - var keyBy = createAggregator(function(result, value, key) { - baseAssignValue(result, key, value); - }); - - /** - * Creates an array of values by running each element in `collection` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, - * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, - * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, - * `template`, `trim`, `trimEnd`, `trimStart`, and `words` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - * @example - * - * function square(n) { - * return n * n; - * } - * - * _.map([4, 8], square); - * // => [16, 64] - * - * _.map({ 'a': 4, 'b': 8 }, square); - * // => [16, 64] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // The `_.property` iteratee shorthand. - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee) { - var func = isArray(collection) ? arrayMap : baseMap; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.sortBy` except that it allows specifying the sort - * orders of the iteratees to sort by. If `orders` is unspecified, all values - * are sorted in ascending order. Otherwise, specify an order of "desc" for - * descending or "asc" for ascending sort order of corresponding values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] - * The iteratees to sort by. - * @param {string[]} [orders] The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 34 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 36 } - * ]; - * - * // Sort by `user` in ascending order and by `age` in descending order. - * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - */ - function orderBy(collection, iteratees, orders, guard) { - if (collection == null) { - return []; - } - if (!isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees]; - } - orders = guard ? undefined : orders; - if (!isArray(orders)) { - orders = orders == null ? [] : [orders]; - } - return baseOrderBy(collection, iteratees, orders); - } - - /** - * Creates an array of elements split into two groups, the first of which - * contains elements `predicate` returns truthy for, the second of which - * contains elements `predicate` returns falsey for. The predicate is - * invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the array of grouped elements. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true }, - * { 'user': 'pebbles', 'age': 1, 'active': false } - * ]; - * - * _.partition(users, function(o) { return o.active; }); - * // => objects for [['fred'], ['barney', 'pebbles']] - * - * // The `_.matches` iteratee shorthand. - * _.partition(users, { 'age': 1, 'active': false }); - * // => objects for [['pebbles'], ['barney', 'fred']] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.partition(users, ['active', false]); - * // => objects for [['barney', 'pebbles'], ['fred']] - * - * // The `_.property` iteratee shorthand. - * _.partition(users, 'active'); - * // => objects for [['fred'], ['barney', 'pebbles']] - */ - var partition = createAggregator(function(result, value, key) { - result[key ? 0 : 1].push(value); - }, function() { return [[], []]; }); - - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` thru `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not given, the first element of `collection` is used as the initial - * value. The iteratee is invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, - * and `sortBy` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduceRight - * @example - * - * _.reduce([1, 2], function(sum, n) { - * return sum + n; - * }, 0); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * return result; - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) - */ - function reduce(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduce : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); - } - - /** - * This method is like `_.reduce` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduce - * @example - * - * var array = [[0, 1], [2, 3], [4, 5]]; - * - * _.reduceRight(array, function(flattened, other) { - * return flattened.concat(other); - * }, []); - * // => [4, 5, 2, 3, 0, 1] - */ - function reduceRight(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduceRight : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); - } - - /** - * The opposite of `_.filter`; this method returns the elements of `collection` - * that `predicate` does **not** return truthy for. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.filter - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true } - * ]; - * - * _.reject(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.reject(users, { 'age': 40, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.reject(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.reject(users, 'active'); - * // => objects for ['barney'] - */ - function reject(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, negate(getIteratee(predicate, 3))); - } - - /** - * Gets a random element from `collection`. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @returns {*} Returns the random element. - * @example - * - * _.sample([1, 2, 3, 4]); - * // => 2 - */ - function sample(collection) { - var func = isArray(collection) ? arraySample : baseSample; - return func(collection); - } - - /** - * Gets `n` random elements at unique keys from `collection` up to the - * size of `collection`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @param {number} [n=1] The number of elements to sample. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the random elements. - * @example - * - * _.sampleSize([1, 2, 3], 2); - * // => [3, 1] - * - * _.sampleSize([1, 2, 3], 4); - * // => [2, 3, 1] - */ - function sampleSize(collection, n, guard) { - if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { - n = 1; - } else { - n = toInteger(n); - } - var func = isArray(collection) ? arraySampleSize : baseSampleSize; - return func(collection, n); - } - - /** - * Creates an array of shuffled values, using a version of the - * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - * @example - * - * _.shuffle([1, 2, 3, 4]); - * // => [4, 1, 3, 2] - */ - function shuffle(collection) { - var func = isArray(collection) ? arrayShuffle : baseShuffle; - return func(collection); - } - - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable string keyed properties for objects. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the collection size. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - if (collection == null) { - return 0; - } - if (isArrayLike(collection)) { - return isString(collection) ? stringSize(collection) : collection.length; - } - var tag = getTag(collection); - if (tag == mapTag || tag == setTag) { - return collection.size; - } - return baseKeys(collection).length; - } - - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * Iteration is stopped once `predicate` returns truthy. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.some(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, guard) { - var func = isArray(collection) ? arraySome : baseSome; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection thru each iteratee. This method - * performs a stable sort, that is, it preserves the original sort order of - * equal elements. The iteratees are invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {...(Function|Function[])} [iteratees=[_.identity]] - * The iteratees to sort by. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.sortBy(users, [function(o) { return o.user; }]); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - * - * _.sortBy(users, ['user', 'age']); - * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] - */ - var sortBy = baseRest(function(collection, iteratees) { - if (collection == null) { - return []; - } - var length = iteratees.length; - if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { - iteratees = []; - } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { - iteratees = [iteratees[0]]; - } - return baseOrderBy(collection, baseFlatten(iteratees, 1), []); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Date - * @returns {number} Returns the timestamp. - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. - */ - var now = ctxNow || function() { - return root.Date.now(); - }; - - /*------------------------------------------------------------------------*/ - - /** - * The opposite of `_.before`; this method creates a function that invokes - * `func` once it's called `n` or more times. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {number} n The number of calls before `func` is invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => Logs 'done saving!' after the two async saves have completed. - */ - function after(n, func) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } - - /** - * Creates a function that invokes `func`, with up to `n` arguments, - * ignoring any additional arguments. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to cap arguments for. - * @param {number} [n=func.length] The arity cap. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new capped function. - * @example - * - * _.map(['6', '8', '10'], _.ary(parseInt, 1)); - * // => [6, 8, 10] - */ - function ary(func, n, guard) { - n = guard ? undefined : n; - n = (func && n == null) ? func.length : n; - return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); - } - - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it's called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery(element).on('click', _.before(5, addContactToList)); - * // => Allows adding up to 4 contacts to the list. - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = undefined; - } - return result; - }; - } - - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and `partials` prepended to the arguments it receives. - * - * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for partially applied arguments. - * - * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" - * property of bound functions. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * function greet(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // Bound with placeholders. - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = baseRest(function(func, thisArg, partials) { - var bitmask = WRAP_BIND_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bind)); - bitmask |= WRAP_PARTIAL_FLAG; - } - return createWrap(func, bitmask, thisArg, partials, holders); - }); - - /** - * Creates a function that invokes the method at `object[key]` with `partials` - * prepended to the arguments it receives. - * - * This method differs from `_.bind` by allowing bound functions to reference - * methods that may be redefined or don't yet exist. See - * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) - * for more details. - * - * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Function - * @param {Object} object The object to invoke the method on. - * @param {string} key The key of the method. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var object = { - * 'user': 'fred', - * 'greet': function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * }; - * - * var bound = _.bindKey(object, 'greet', 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * object.greet = function(greeting, punctuation) { - * return greeting + 'ya ' + this.user + punctuation; - * }; - * - * bound('!'); - * // => 'hiya fred!' - * - * // Bound with placeholders. - * var bound = _.bindKey(object, 'greet', _, '!'); - * bound('hi'); - * // => 'hiya fred!' - */ - var bindKey = baseRest(function(object, key, partials) { - var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bindKey)); - bitmask |= WRAP_PARTIAL_FLAG; - } - return createWrap(key, bitmask, object, partials, holders); - }); - - /** - * Creates a function that accepts arguments of `func` and either invokes - * `func` returning its result, if at least `arity` number of arguments have - * been provided, or returns a function that accepts the remaining `func` - * arguments, and so on. The arity of `func` may be specified if `func.length` - * is not sufficient. - * - * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for provided arguments. - * - * **Note:** This method doesn't set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curry(abc); - * - * curried(1)(2)(3); - * // => [1, 2, 3] - * - * curried(1, 2)(3); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // Curried with placeholders. - * curried(1)(_, 3)(2); - * // => [1, 2, 3] - */ - function curry(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curry.placeholder; - return result; - } - - /** - * This method is like `_.curry` except that arguments are applied to `func` - * in the manner of `_.partialRight` instead of `_.partial`. - * - * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for provided arguments. - * - * **Note:** This method doesn't set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curryRight(abc); - * - * curried(3)(2)(1); - * // => [1, 2, 3] - * - * curried(2, 3)(1); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // Curried with placeholders. - * curried(3)(1, _)(2); - * // => [1, 2, 3] - */ - function curryRight(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curryRight.placeholder; - return result; - } - - /** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // Avoid costly calculations while the window size is in flux. - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); - * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); - */ - function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; - - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } - - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - timeWaiting = wait - timeSinceLastCall; - - return maxing - ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) - : timeWaiting; - } - - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; - - // Either this is the first call, activity has stopped and we're at the - // trailing edge, the system time has gone backwards and we're treating - // it as the trailing edge, or we've hit the `maxWait` limit. - return (lastCallTime === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } - - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } - - function trailingEdge(time) { - timerId = undefined; - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } - - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; - } - - function flush() { - return timerId === undefined ? result : trailingEdge(now()); - } - - function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); - - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; - } - - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // => Logs 'deferred' after one millisecond. - */ - var defer = baseRest(function(func, args) { - return baseDelay(func, 1, args); - }); - - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => Logs 'later' after one second. - */ - var delay = baseRest(function(func, wait, args) { - return baseDelay(func, toNumber(wait) || 0, args); - }); - - /** - * Creates a function that invokes `func` with arguments reversed. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to flip arguments for. - * @returns {Function} Returns the new flipped function. - * @example - * - * var flipped = _.flip(function() { - * return _.toArray(arguments); - * }); - * - * flipped('a', 'b', 'c', 'd'); - * // => ['d', 'c', 'b', 'a'] - */ - function flip(func) { - return createWrap(func, WRAP_FLIP_FLAG); - } - - /** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided, it determines the cache key for storing the result based on the - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is used as the map cache key. The `func` - * is invoked with the `this` binding of the memoized function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the - * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `clear`, `delete`, `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoized function. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; - * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] - * - * values(other); - * // => [3, 4] - * - * object.a = 2; - * values(object); - * // => [1, 2] - * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] - * - * // Replace `_.memoize.Cache`. - * _.memoize.Cache = WeakMap; - */ - function memoize(func, resolver) { - if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function() { - var args = arguments, - key = resolver ? resolver.apply(this, args) : args[0], - cache = memoized.cache; - - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - memoized.cache = cache.set(key, result) || cache; - return result; - }; - memoized.cache = new (memoize.Cache || MapCache); - return memoized; - } - - // Expose `MapCache`. - memoize.Cache = MapCache; - - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new negated function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - var args = arguments; - switch (args.length) { - case 0: return !predicate.call(this); - case 1: return !predicate.call(this, args[0]); - case 2: return !predicate.call(this, args[0], args[1]); - case 3: return !predicate.call(this, args[0], args[1], args[2]); - } - return !predicate.apply(this, args); - }; - } - - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first invocation. The `func` is - * invoked with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // => `createApplication` is invoked once - */ - function once(func) { - return before(2, func); - } - - /** - * Creates a function that invokes `func` with its arguments transformed. - * - * @static - * @since 4.0.0 - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms=[_.identity]] - * The argument transforms. - * @returns {Function} Returns the new function. - * @example - * - * function doubled(n) { - * return n * 2; - * } - * - * function square(n) { - * return n * n; - * } - * - * var func = _.overArgs(function(x, y) { - * return [x, y]; - * }, [square, doubled]); - * - * func(9, 3); - * // => [81, 6] - * - * func(10, 5); - * // => [100, 10] - */ - var overArgs = castRest(function(func, transforms) { - transforms = (transforms.length == 1 && isArray(transforms[0])) - ? arrayMap(transforms[0], baseUnary(getIteratee())) - : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); - - var funcsLength = transforms.length; - return baseRest(function(args) { - var index = -1, - length = nativeMin(args.length, funcsLength); - - while (++index < length) { - args[index] = transforms[index].call(this, args[index]); - } - return apply(func, this, args); - }); - }); - - /** - * Creates a function that invokes `func` with `partials` prepended to the - * arguments it receives. This method is like `_.bind` except it does **not** - * alter the `this` binding. - * - * The `_.partial.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method doesn't set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @since 0.2.0 - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * function greet(greeting, name) { - * return greeting + ' ' + name; - * } - * - * var sayHelloTo = _.partial(greet, 'hello'); - * sayHelloTo('fred'); - * // => 'hello fred' - * - * // Partially applied with placeholders. - * var greetFred = _.partial(greet, _, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - */ - var partial = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partial)); - return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); - }); - - /** - * This method is like `_.partial` except that partially applied arguments - * are appended to the arguments it receives. - * - * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method doesn't set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * function greet(greeting, name) { - * return greeting + ' ' + name; - * } - * - * var greetFred = _.partialRight(greet, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - * - * // Partially applied with placeholders. - * var sayHelloTo = _.partialRight(greet, 'hello', _); - * sayHelloTo('fred'); - * // => 'hello fred' - */ - var partialRight = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partialRight)); - return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); - }); - - /** - * Creates a function that invokes `func` with arguments arranged according - * to the specified `indexes` where the argument value at the first index is - * provided as the first argument, the argument value at the second index is - * provided as the second argument, and so on. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to rearrange arguments for. - * @param {...(number|number[])} indexes The arranged argument indexes. - * @returns {Function} Returns the new function. - * @example - * - * var rearged = _.rearg(function(a, b, c) { - * return [a, b, c]; - * }, [2, 0, 1]); - * - * rearged('b', 'c', 'a') - * // => ['a', 'b', 'c'] - */ - var rearg = flatRest(function(func, indexes) { - return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); - }); - - /** - * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as - * an array. - * - * **Note:** This method is based on the - * [rest parameter](https://mdn.io/rest_parameters). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.rest(function(what, names) { - * return what + ' ' + _.initial(names).join(', ') + - * (_.size(names) > 1 ? ', & ' : '') + _.last(names); - * }); - * - * say('hello', 'fred', 'barney', 'pebbles'); - * // => 'hello fred, barney, & pebbles' - */ - function rest(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = start === undefined ? start : toInteger(start); - return baseRest(func, start); - } - - /** - * Creates a function that invokes `func` with the `this` binding of the - * create function and an array of arguments much like - * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). - * - * **Note:** This method is based on the - * [spread operator](https://mdn.io/spread_operator). - * - * @static - * @memberOf _ - * @since 3.2.0 - * @category Function - * @param {Function} func The function to spread arguments over. - * @param {number} [start=0] The start position of the spread. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.spread(function(who, what) { - * return who + ' says ' + what; - * }); - * - * say(['fred', 'hello']); - * // => 'fred says hello' - * - * var numbers = Promise.all([ - * Promise.resolve(40), - * Promise.resolve(36) - * ]); - * - * numbers.then(_.spread(function(x, y) { - * return x + y; - * })); - * // => a Promise of 76 - */ - function spread(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = start == null ? 0 : nativeMax(toInteger(start), 0); - return baseRest(function(args) { - var array = args[start], - otherArgs = castSlice(args, 0, start); - - if (array) { - arrayPush(otherArgs, array); - } - return apply(func, this, otherArgs); - }); - } - - /** - * Creates a throttled function that only invokes `func` at most once per - * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed `func` invocations and a `flush` method to - * immediately invoke them. Provide `options` to indicate whether `func` - * should be invoked on the leading and/or trailing edge of the `wait` - * timeout. The `func` is invoked with the last arguments provided to the - * throttled function. Subsequent calls to the throttled function return the - * result of the last `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the throttled function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=true] - * Specify invoking on the leading edge of the timeout. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // Avoid excessively updating the position while scrolling. - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. - * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); - * jQuery(element).on('click', throttled); - * - * // Cancel the trailing throttled invocation. - * jQuery(window).on('popstate', throttled.cancel); - */ - function throttle(func, wait, options) { - var leading = true, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - return debounce(func, wait, { - 'leading': leading, - 'maxWait': wait, - 'trailing': trailing - }); - } - - /** - * Creates a function that accepts up to one argument, ignoring any - * additional arguments. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - * @example - * - * _.map(['6', '8', '10'], _.unary(parseInt)); - * // => [6, 8, 10] - */ - function unary(func) { - return ary(func, 1); - } - - /** - * Creates a function that provides `value` to `wrapper` as its first - * argument. Any additional arguments provided to the function are appended - * to those provided to the `wrapper`. The wrapper is invoked with the `this` - * binding of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {*} value The value to wrap. - * @param {Function} [wrapper=identity] The wrapper function. - * @returns {Function} Returns the new function. - * @example - * - * var p = _.wrap(_.escape, function(func, text) { - * return '

    ' + func(text) + '

    '; - * }); - * - * p('fred, barney, & pebbles'); - * // => '

    fred, barney, & pebbles

    ' - */ - function wrap(value, wrapper) { - return partial(castFunction(wrapper), value); - } - - /*------------------------------------------------------------------------*/ - - /** - * Casts `value` as an array if it's not one. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Lang - * @param {*} value The value to inspect. - * @returns {Array} Returns the cast array. - * @example - * - * _.castArray(1); - * // => [1] - * - * _.castArray({ 'a': 1 }); - * // => [{ 'a': 1 }] - * - * _.castArray('abc'); - * // => ['abc'] - * - * _.castArray(null); - * // => [null] - * - * _.castArray(undefined); - * // => [undefined] - * - * _.castArray(); - * // => [] - * - * var array = [1, 2, 3]; - * console.log(_.castArray(array) === array); - * // => true - */ - function castArray() { - if (!arguments.length) { - return []; - } - var value = arguments[0]; - return isArray(value) ? value : [value]; - } - - /** - * Creates a shallow clone of `value`. - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) - * and supports cloning arrays, array buffers, booleans, date objects, maps, - * numbers, `Object` objects, regexes, sets, strings, symbols, and typed - * arrays. The own enumerable properties of `arguments` objects are cloned - * as plain objects. An empty object is returned for uncloneable values such - * as error objects, functions, DOM nodes, and WeakMaps. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to clone. - * @returns {*} Returns the cloned value. - * @see _.cloneDeep - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var shallow = _.clone(objects); - * console.log(shallow[0] === objects[0]); - * // => true - */ - function clone(value) { - return baseClone(value, CLONE_SYMBOLS_FLAG); - } - - /** - * This method is like `_.clone` except that it accepts `customizer` which - * is invoked to produce the cloned value. If `customizer` returns `undefined`, - * cloning is handled by the method instead. The `customizer` is invoked with - * up to four arguments; (value [, index|key, object, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the cloned value. - * @see _.cloneDeepWith - * @example - * - * function customizer(value) { - * if (_.isElement(value)) { - * return value.cloneNode(false); - * } - * } - * - * var el = _.cloneWith(document.body, customizer); - * - * console.log(el === document.body); - * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); - * // => 0 - */ - function cloneWith(value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); - } - - /** - * This method is like `_.clone` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @returns {*} Returns the deep cloned value. - * @see _.clone - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var deep = _.cloneDeep(objects); - * console.log(deep[0] === objects[0]); - * // => false - */ - function cloneDeep(value) { - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); - } - - /** - * This method is like `_.cloneWith` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the deep cloned value. - * @see _.cloneWith - * @example - * - * function customizer(value) { - * if (_.isElement(value)) { - * return value.cloneNode(true); - * } - * } - * - * var el = _.cloneDeepWith(document.body, customizer); - * - * console.log(el === document.body); - * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); - * // => 20 - */ - function cloneDeepWith(value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); - } - - /** - * Checks if `object` conforms to `source` by invoking the predicate - * properties of `source` with the corresponding property values of `object`. - * - * **Note:** This method is equivalent to `_.conforms` when `source` is - * partially applied. - * - * @static - * @memberOf _ - * @since 4.14.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); - * // => true - * - * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); - * // => false - */ - function conformsTo(object, source) { - return source == null || baseConformsTo(object, source, keys(source)); - } - - /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ - function eq(value, other) { - return value === other || (value !== value && other !== other); - } - - /** - * Checks if `value` is greater than `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - * @see _.lt - * @example - * - * _.gt(3, 1); - * // => true - * - * _.gt(3, 3); - * // => false - * - * _.gt(1, 3); - * // => false - */ - var gt = createRelationalOperation(baseGt); - - /** - * Checks if `value` is greater than or equal to `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than or equal to - * `other`, else `false`. - * @see _.lte - * @example - * - * _.gte(3, 1); - * // => true - * - * _.gte(3, 3); - * // => true - * - * _.gte(1, 3); - * // => false - */ - var gte = createRelationalOperation(function(value, other) { - return value >= other; - }); - - /** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && - !propertyIsEnumerable.call(value, 'callee'); - }; - - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ - var isArray = Array.isArray; - - /** - * Checks if `value` is classified as an `ArrayBuffer` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - * @example - * - * _.isArrayBuffer(new ArrayBuffer(2)); - * // => true - * - * _.isArrayBuffer(new Array(2)); - * // => false - */ - var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; - - /** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } - - /** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ - function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); - } - - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || - (isObjectLike(value) && baseGetTag(value) == boolTag); - } - - /** - * Checks if `value` is a buffer. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. - * @example - * - * _.isBuffer(new Buffer(2)); - * // => true - * - * _.isBuffer(new Uint8Array(2)); - * // => false - */ - var isBuffer = nativeIsBuffer || stubFalse; - - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; - - /** - * Checks if `value` is likely a DOM element. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. - * @example - * - * _.isElement(document.body); - * // => true - * - * _.isElement(''); - * // => false - */ - function isElement(value) { - return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); - } - - /** - * Checks if `value` is an empty object, collection, map, or set. - * - * Objects are considered empty if they have no own enumerable string keyed - * properties. - * - * Array-like values such as `arguments` objects, arrays, buffers, strings, or - * jQuery-like collections are considered empty if they have a `length` of `0`. - * Similarly, maps and sets are considered empty if they have a `size` of `0`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (value == null) { - return true; - } - if (isArrayLike(value) && - (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || - isBuffer(value) || isTypedArray(value) || isArguments(value))) { - return !value.length; - } - var tag = getTag(value); - if (tag == mapTag || tag == setTag) { - return !value.size; - } - if (isPrototype(value)) { - return !baseKeys(value).length; - } - for (var key in value) { - if (hasOwnProperty.call(value, key)) { - return false; - } - } - return true; - } - - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. - * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are compared by strict equality, i.e. `===`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.isEqual(object, other); - * // => true - * - * object === other; - * // => false - */ - function isEqual(value, other) { - return baseIsEqual(value, other); - } - - /** - * This method is like `_.isEqual` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with up to - * six arguments: (objValue, othValue [, index|key, object, other, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, othValue) { - * if (isGreeting(objValue) && isGreeting(othValue)) { - * return true; - * } - * } - * - * var array = ['hello', 'goodbye']; - * var other = ['hi', 'goodbye']; - * - * _.isEqualWith(array, other, customizer); - * // => true - */ - function isEqualWith(value, other, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; - } - - /** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an error object, else `false`. - * @example - * - * _.isError(new Error); - * // => true - * - * _.isError(Error); - * // => false - */ - function isError(value) { - if (!isObjectLike(value)) { - return false; - } - var tag = baseGetTag(value); - return tag == errorTag || tag == domExcTag || - (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); - } - - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on - * [`Number.isFinite`](https://mdn.io/Number/isFinite). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(3); - * // => true - * - * _.isFinite(Number.MIN_VALUE); - * // => true - * - * _.isFinite(Infinity); - * // => false - * - * _.isFinite('3'); - * // => false - */ - function isFinite(value) { - return typeof value == 'number' && nativeIsFinite(value); - } - - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - function isFunction(value) { - if (!isObject(value)) { - return false; - } - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 9 which returns 'object' for typed arrays and other constructors. - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; - } - - /** - * Checks if `value` is an integer. - * - * **Note:** This method is based on - * [`Number.isInteger`](https://mdn.io/Number/isInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an integer, else `false`. - * @example - * - * _.isInteger(3); - * // => true - * - * _.isInteger(Number.MIN_VALUE); - * // => false - * - * _.isInteger(Infinity); - * // => false - * - * _.isInteger('3'); - * // => false - */ - function isInteger(value) { - return typeof value == 'number' && value == toInteger(value); - } - - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ - function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ - function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); - } - - /** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ - function isObjectLike(value) { - return value != null && typeof value == 'object'; - } - - /** - * Checks if `value` is classified as a `Map` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - * @example - * - * _.isMap(new Map); - * // => true - * - * _.isMap(new WeakMap); - * // => false - */ - var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; - - /** - * Performs a partial deep comparison between `object` and `source` to - * determine if `object` contains equivalent property values. - * - * **Note:** This method is equivalent to `_.matches` when `source` is - * partially applied. - * - * Partial comparisons will match empty array and empty object `source` - * values against any array or object value, respectively. See `_.isEqual` - * for a list of supported value comparisons. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.isMatch(object, { 'b': 2 }); - * // => true - * - * _.isMatch(object, { 'b': 1 }); - * // => false - */ - function isMatch(object, source) { - return object === source || baseIsMatch(object, source, getMatchData(source)); - } - - /** - * This method is like `_.isMatch` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with five - * arguments: (objValue, srcValue, index|key, object, source). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, srcValue) { - * if (isGreeting(objValue) && isGreeting(srcValue)) { - * return true; - * } - * } - * - * var object = { 'greeting': 'hello' }; - * var source = { 'greeting': 'hi' }; - * - * _.isMatchWith(object, source, customizer); - * // => true - */ - function isMatchWith(object, source, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseIsMatch(object, source, getMatchData(source), customizer); - } - - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is based on - * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as - * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for - * `undefined` and other non-number values. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some - // ActiveX objects in IE. - return isNumber(value) && value != +value; - } - - /** - * Checks if `value` is a pristine native function. - * - * **Note:** This method can't reliably detect native functions in the presence - * of the core-js package because core-js circumvents this kind of detection. - * Despite multiple requests, the core-js maintainer has made it clear: any - * attempt to fix the detection will be obstructed. As a result, we're left - * with little choice but to throw an error. Unfortunately, this also affects - * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), - * which rely on core-js. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ - function isNative(value) { - if (isMaskable(value)) { - throw new Error(CORE_ERROR_TEXT); - } - return baseIsNative(value); - } - - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } - - /** - * Checks if `value` is `null` or `undefined`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is nullish, else `false`. - * @example - * - * _.isNil(null); - * // => true - * - * _.isNil(void 0); - * // => true - * - * _.isNil(NaN); - * // => false - */ - function isNil(value) { - return value == null; - } - - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are - * classified as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a number, else `false`. - * @example - * - * _.isNumber(3); - * // => true - * - * _.isNumber(Number.MIN_VALUE); - * // => true - * - * _.isNumber(Infinity); - * // => true - * - * _.isNumber('3'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || - (isObjectLike(value) && baseGetTag(value) == numberTag); - } - - /** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * @static - * @memberOf _ - * @since 0.8.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ - function isPlainObject(value) { - if (!isObjectLike(value) || baseGetTag(value) != objectTag) { - return false; - } - var proto = getPrototype(value); - if (proto === null) { - return true; - } - var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return typeof Ctor == 'function' && Ctor instanceof Ctor && - funcToString.call(Ctor) == objectCtorString; - } - - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; - - /** - * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 - * double precision number which isn't the result of a rounded unsafe integer. - * - * **Note:** This method is based on - * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. - * @example - * - * _.isSafeInteger(3); - * // => true - * - * _.isSafeInteger(Number.MIN_VALUE); - * // => false - * - * _.isSafeInteger(Infinity); - * // => false - * - * _.isSafeInteger('3'); - * // => false - */ - function isSafeInteger(value) { - return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is classified as a `Set` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - * @example - * - * _.isSet(new Set); - * // => true - * - * _.isSet(new WeakSet); - * // => false - */ - var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; - - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a string, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); - } - - /** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ - function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && baseGetTag(value) == symbolTag); - } - - /** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ - var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; - - /** - * Checks if `value` is `undefined`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; - } - - /** - * Checks if `value` is classified as a `WeakMap` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. - * @example - * - * _.isWeakMap(new WeakMap); - * // => true - * - * _.isWeakMap(new Map); - * // => false - */ - function isWeakMap(value) { - return isObjectLike(value) && getTag(value) == weakMapTag; - } - - /** - * Checks if `value` is classified as a `WeakSet` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. - * @example - * - * _.isWeakSet(new WeakSet); - * // => true - * - * _.isWeakSet(new Set); - * // => false - */ - function isWeakSet(value) { - return isObjectLike(value) && baseGetTag(value) == weakSetTag; - } - - /** - * Checks if `value` is less than `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - * @see _.gt - * @example - * - * _.lt(1, 3); - * // => true - * - * _.lt(3, 3); - * // => false - * - * _.lt(3, 1); - * // => false - */ - var lt = createRelationalOperation(baseLt); - - /** - * Checks if `value` is less than or equal to `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than or equal to - * `other`, else `false`. - * @see _.gte - * @example - * - * _.lte(1, 3); - * // => true - * - * _.lte(3, 3); - * // => true - * - * _.lte(3, 1); - * // => false - */ - var lte = createRelationalOperation(function(value, other) { - return value <= other; - }); - - /** - * Converts `value` to an array. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * _.toArray({ 'a': 1, 'b': 2 }); - * // => [1, 2] - * - * _.toArray('abc'); - * // => ['a', 'b', 'c'] - * - * _.toArray(1); - * // => [] - * - * _.toArray(null); - * // => [] - */ - function toArray(value) { - if (!value) { - return []; - } - if (isArrayLike(value)) { - return isString(value) ? stringToArray(value) : copyArray(value); - } - if (symIterator && value[symIterator]) { - return iteratorToArray(value[symIterator]()); - } - var tag = getTag(value), - func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); - - return func(value); - } - - /** - * Converts `value` to a finite number. - * - * @static - * @memberOf _ - * @since 4.12.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted number. - * @example - * - * _.toFinite(3.2); - * // => 3.2 - * - * _.toFinite(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toFinite(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toFinite('3.2'); - * // => 3.2 - */ - function toFinite(value) { - if (!value) { - return value === 0 ? value : 0; - } - value = toNumber(value); - if (value === INFINITY || value === -INFINITY) { - var sign = (value < 0 ? -1 : 1); - return sign * MAX_INTEGER; - } - return value === value ? value : 0; - } - - /** - * Converts `value` to an integer. - * - * **Note:** This method is loosely based on - * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toInteger(3.2); - * // => 3 - * - * _.toInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toInteger(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toInteger('3.2'); - * // => 3 - */ - function toInteger(value) { - var result = toFinite(value), - remainder = result % 1; - - return result === result ? (remainder ? result - remainder : result) : 0; - } - - /** - * Converts `value` to an integer suitable for use as the length of an - * array-like object. - * - * **Note:** This method is based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toLength(3.2); - * // => 3 - * - * _.toLength(Number.MIN_VALUE); - * // => 0 - * - * _.toLength(Infinity); - * // => 4294967295 - * - * _.toLength('3.2'); - * // => 3 - */ - function toLength(value) { - return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; - } - - /** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ - function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); - } - - /** - * Converts `value` to a plain object flattening inherited enumerable string - * keyed properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ - function toPlainObject(value) { - return copyObject(value, keysIn(value)); - } - - /** - * Converts `value` to a safe integer. A safe integer can be compared and - * represented correctly. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toSafeInteger(3.2); - * // => 3 - * - * _.toSafeInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toSafeInteger(Infinity); - * // => 9007199254740991 - * - * _.toSafeInteger('3.2'); - * // => 3 - */ - function toSafeInteger(value) { - return value - ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) - : (value === 0 ? value : 0); - } - - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ - function toString(value) { - return value == null ? '' : baseToString(value); - } - - /*------------------------------------------------------------------------*/ - - /** - * Assigns own enumerable string keyed properties of source objects to the - * destination object. Source objects are applied from left to right. - * Subsequent sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object` and is loosely based on - * [`Object.assign`](https://mdn.io/Object/assign). - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assignIn - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assign({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'c': 3 } - */ - var assign = createAssigner(function(object, source) { - if (isPrototype(source) || isArrayLike(source)) { - copyObject(source, keys(source), object); - return; - } - for (var key in source) { - if (hasOwnProperty.call(source, key)) { - assignValue(object, key, source[key]); - } - } - }); - - /** - * This method is like `_.assign` except that it iterates over own and - * inherited source properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assign - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assignIn({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } - */ - var assignIn = createAssigner(function(object, source) { - copyObject(source, keysIn(source), object); - }); - - /** - * This method is like `_.assignIn` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extendWith - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignInWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keysIn(source), object, customizer); - }); - - /** - * This method is like `_.assign` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignInWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keys(source), object, customizer); - }); - - /** - * Creates an array of values corresponding to `paths` of `object`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Array} Returns the picked values. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _.at(object, ['a[0].b.c', 'a[1]']); - * // => [3, 4] - */ - var at = flatRest(baseAt); - - /** - * Creates an object that inherits from the `prototype` object. If a - * `properties` object is given, its own enumerable string keyed properties - * are assigned to the created object. - * - * @static - * @memberOf _ - * @since 2.3.0 - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties) { - var result = baseCreate(prototype); - return properties == null ? result : baseAssign(result, properties); - } - - /** - * Assigns own and inherited enumerable string keyed properties of source - * objects to the destination object for all destination properties that - * resolve to `undefined`. Source objects are applied from left to right. - * Once a property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaultsDeep - * @example - * - * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var defaults = baseRest(function(object, sources) { - object = Object(object); - - var index = -1; - var length = sources.length; - var guard = length > 2 ? sources[2] : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - length = 1; - } - - while (++index < length) { - var source = sources[index]; - var props = keysIn(source); - var propsIndex = -1; - var propsLength = props.length; - - while (++propsIndex < propsLength) { - var key = props[propsIndex]; - var value = object[key]; - - if (value === undefined || - (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { - object[key] = source[key]; - } - } - } - - return object; - }); - - /** - * This method is like `_.defaults` except that it recursively assigns - * default properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaults - * @example - * - * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); - * // => { 'a': { 'b': 2, 'c': 3 } } - */ - var defaultsDeep = baseRest(function(args) { - args.push(undefined, customDefaultsMerge); - return apply(mergeWith, undefined, args); - }); - - /** - * This method is like `_.find` except that it returns the key of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findKey(users, function(o) { return o.age < 40; }); - * // => 'barney' (iteration order is not guaranteed) - * - * // The `_.matches` iteratee shorthand. - * _.findKey(users, { 'age': 1, 'active': true }); - * // => 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findKey(users, 'active'); - * // => 'barney' - */ - function findKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); - } - - /** - * This method is like `_.findKey` except that it iterates over elements of - * a collection in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findLastKey(users, function(o) { return o.age < 40; }); - * // => returns 'pebbles' assuming `_.findKey` returns 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.findLastKey(users, { 'age': 36, 'active': true }); - * // => 'barney' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findLastKey(users, 'active'); - * // => 'pebbles' - */ - function findLastKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); - } - - /** - * Iterates over own and inherited enumerable string keyed properties of an - * object and invokes `iteratee` for each property. The iteratee is invoked - * with three arguments: (value, key, object). Iteratee functions may exit - * iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 0.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forInRight - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forIn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). - */ - function forIn(object, iteratee) { - return object == null - ? object - : baseFor(object, getIteratee(iteratee, 3), keysIn); - } - - /** - * This method is like `_.forIn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forIn - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forInRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. - */ - function forInRight(object, iteratee) { - return object == null - ? object - : baseForRight(object, getIteratee(iteratee, 3), keysIn); - } - - /** - * Iterates over own enumerable string keyed properties of an object and - * invokes `iteratee` for each property. The iteratee is invoked with three - * arguments: (value, key, object). Iteratee functions may exit iteration - * early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 0.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forOwnRight - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forOwn(object, iteratee) { - return object && baseForOwn(object, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.forOwn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forOwn - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwnRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. - */ - function forOwnRight(object, iteratee) { - return object && baseForOwnRight(object, getIteratee(iteratee, 3)); - } - - /** - * Creates an array of function property names from own enumerable properties - * of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functionsIn - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functions(new Foo); - * // => ['a', 'b'] - */ - function functions(object) { - return object == null ? [] : baseFunctions(object, keys(object)); - } - - /** - * Creates an array of function property names from own and inherited - * enumerable properties of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functions - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functionsIn(new Foo); - * // => ['a', 'b', 'c'] - */ - function functionsIn(object) { - return object == null ? [] : baseFunctions(object, keysIn(object)); - } - - /** - * Gets the value at `path` of `object`. If the resolved value is - * `undefined`, the `defaultValue` is returned in its place. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ - function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, path); - return result === undefined ? defaultValue : result; - } - - /** - * Checks if `path` is a direct property of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = { 'a': { 'b': 2 } }; - * var other = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b'); - * // => true - * - * _.has(object, ['a', 'b']); - * // => true - * - * _.has(other, 'a'); - * // => false - */ - function has(object, path) { - return object != null && hasPath(object, path, baseHas); - } - - /** - * Checks if `path` is a direct or inherited property of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.hasIn(object, 'a'); - * // => true - * - * _.hasIn(object, 'a.b'); - * // => true - * - * _.hasIn(object, ['a', 'b']); - * // => true - * - * _.hasIn(object, 'b'); - * // => false - */ - function hasIn(object, path) { - return object != null && hasPath(object, path, baseHasIn); - } - - /** - * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite - * property assignments of previous values. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Object - * @param {Object} object The object to invert. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invert(object); - * // => { '1': 'c', '2': 'b' } - */ - var invert = createInverter(function(result, value, key) { - if (value != null && - typeof value.toString != 'function') { - value = nativeObjectToString.call(value); - } - - result[value] = key; - }, constant(identity)); - - /** - * This method is like `_.invert` except that the inverted object is generated - * from the results of running each element of `object` thru `iteratee`. The - * corresponding inverted value of each inverted key is an array of keys - * responsible for generating the inverted value. The iteratee is invoked - * with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Object - * @param {Object} object The object to invert. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invertBy(object); - * // => { '1': ['a', 'c'], '2': ['b'] } - * - * _.invertBy(object, function(value) { - * return 'group' + value; - * }); - * // => { 'group1': ['a', 'c'], 'group2': ['b'] } - */ - var invertBy = createInverter(function(result, value, key) { - if (value != null && - typeof value.toString != 'function') { - value = nativeObjectToString.call(value); - } - - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - }, getIteratee); - - /** - * Invokes the method at `path` of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {...*} [args] The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - * @example - * - * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; - * - * _.invoke(object, 'a[0].b.c.slice', 1, 3); - * // => [2, 3] - */ - var invoke = baseRest(baseInvoke); - - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); - } - - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - function keysIn(object) { - return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); - } - - /** - * The opposite of `_.mapValues`; this method creates an object with the - * same values as `object` and keys generated by running each own enumerable - * string keyed property of `object` thru `iteratee`. The iteratee is invoked - * with three arguments: (value, key, object). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns the new mapped object. - * @see _.mapValues - * @example - * - * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { - * return key + value; - * }); - * // => { 'a1': 1, 'b2': 2 } - */ - function mapKeys(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); - - baseForOwn(object, function(value, key, object) { - baseAssignValue(result, iteratee(value, key, object), value); - }); - return result; - } - - /** - * Creates an object with the same keys as `object` and values generated - * by running each own enumerable string keyed property of `object` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, key, object). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns the new mapped object. - * @see _.mapKeys - * @example - * - * var users = { - * 'fred': { 'user': 'fred', 'age': 40 }, - * 'pebbles': { 'user': 'pebbles', 'age': 1 } - * }; - * - * _.mapValues(users, function(o) { return o.age; }); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - * - * // The `_.property` iteratee shorthand. - * _.mapValues(users, 'age'); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - */ - function mapValues(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); - - baseForOwn(object, function(value, key, object) { - baseAssignValue(result, key, iteratee(value, key, object)); - }); - return result; - } - - /** - * This method is like `_.assign` except that it recursively merges own and - * inherited enumerable string keyed properties of source objects into the - * destination object. Source properties that resolve to `undefined` are - * skipped if a destination value exists. Array and plain object properties - * are merged recursively. Other objects and value types are overridden by - * assignment. Source objects are applied from left to right. Subsequent - * sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * var object = { - * 'a': [{ 'b': 2 }, { 'd': 4 }] - * }; - * - * var other = { - * 'a': [{ 'c': 3 }, { 'e': 5 }] - * }; - * - * _.merge(object, other); - * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } - */ - var merge = createAssigner(function(object, source, srcIndex) { - baseMerge(object, source, srcIndex); - }); - - /** - * This method is like `_.merge` except that it accepts `customizer` which - * is invoked to produce the merged values of the destination and source - * properties. If `customizer` returns `undefined`, merging is handled by the - * method instead. The `customizer` is invoked with six arguments: - * (objValue, srcValue, key, object, source, stack). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * function customizer(objValue, srcValue) { - * if (_.isArray(objValue)) { - * return objValue.concat(srcValue); - * } - * } - * - * var object = { 'a': [1], 'b': [2] }; - * var other = { 'a': [3], 'b': [4] }; - * - * _.mergeWith(object, other, customizer); - * // => { 'a': [1, 3], 'b': [2, 4] } - */ - var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { - baseMerge(object, source, srcIndex, customizer); - }); - - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable property paths of `object` that are not omitted. - * - * **Note:** This method is considerably slower than `_.pick`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [paths] The property paths to omit. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omit(object, ['a', 'c']); - * // => { 'b': '2' } - */ - var omit = flatRest(function(object, paths) { - var result = {}; - if (object == null) { - return result; - } - var isDeep = false; - paths = arrayMap(paths, function(path) { - path = castPath(path, object); - isDeep || (isDeep = path.length > 1); - return path; - }); - copyObject(object, getAllKeysIn(object), result); - if (isDeep) { - result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); - } - var length = paths.length; - while (length--) { - baseUnset(result, paths[length]); - } - return result; - }); - - /** - * The opposite of `_.pickBy`; this method creates an object composed of - * the own and inherited enumerable string keyed properties of `object` that - * `predicate` doesn't return truthy for. The predicate is invoked with two - * arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omitBy(object, _.isNumber); - * // => { 'b': '2' } - */ - function omitBy(object, predicate) { - return pickBy(object, negate(getIteratee(predicate))); - } - - /** - * Creates an object composed of the picked `object` properties. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pick(object, ['a', 'c']); - * // => { 'a': 1, 'c': 3 } - */ - var pick = flatRest(function(object, paths) { - return object == null ? {} : basePick(object, paths); - }); - - /** - * Creates an object composed of the `object` properties `predicate` returns - * truthy for. The predicate is invoked with two arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pickBy(object, _.isNumber); - * // => { 'a': 1, 'c': 3 } - */ - function pickBy(object, predicate) { - if (object == null) { - return {}; - } - var props = arrayMap(getAllKeysIn(object), function(prop) { - return [prop]; - }); - predicate = getIteratee(predicate); - return basePickBy(object, props, function(value, path) { - return predicate(value, path[0]); - }); - } - - /** - * This method is like `_.get` except that if the resolved value is a - * function it's invoked with the `this` binding of its parent object and - * its result is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a[0].b.c3', 'default'); - * // => 'default' - * - * _.result(object, 'a[0].b.c3', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - path = castPath(path, object); - - var index = -1, - length = path.length; - - // Ensure the loop is entered when path is empty. - if (!length) { - length = 1; - object = undefined; - } - while (++index < length) { - var value = object == null ? undefined : object[toKey(path[index])]; - if (value === undefined) { - index = length; - value = defaultValue; - } - object = isFunction(value) ? value.call(object) : value; - } - return object; - } - - /** - * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, - * it's created. Arrays are created for missing index properties while objects - * are created for all other missing properties. Use `_.setWith` to customize - * `path` creation. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.set(object, 'a[0].b.c', 4); - * console.log(object.a[0].b.c); - * // => 4 - * - * _.set(object, ['x', '0', 'y', 'z'], 5); - * console.log(object.x[0].y.z); - * // => 5 - */ - function set(object, path, value) { - return object == null ? object : baseSet(object, path, value); - } - - /** - * This method is like `_.set` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.setWith(object, '[0][1]', 'a', Object); - * // => { '0': { '1': 'a' } } - */ - function setWith(object, path, value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseSet(object, path, value, customizer); - } - - /** - * Creates an array of own enumerable string keyed-value pairs for `object` - * which can be consumed by `_.fromPairs`. If `object` is a map or set, its - * entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entries - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairs(new Foo); - * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) - */ - var toPairs = createToPairs(keys); - - /** - * Creates an array of own and inherited enumerable string keyed-value pairs - * for `object` which can be consumed by `_.fromPairs`. If `object` is a map - * or set, its entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entriesIn - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairsIn(new Foo); - * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) - */ - var toPairsIn = createToPairs(keysIn); - - /** - * An alternative to `_.reduce`; this method transforms `object` to a new - * `accumulator` object which is the result of running each of its own - * enumerable string keyed properties thru `iteratee`, with each invocation - * potentially mutating the `accumulator` object. If `accumulator` is not - * provided, a new object with the same `[[Prototype]]` will be used. The - * iteratee is invoked with four arguments: (accumulator, value, key, object). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The custom accumulator value. - * @returns {*} Returns the accumulated value. - * @example - * - * _.transform([2, 3, 4], function(result, n) { - * result.push(n *= n); - * return n % 2 == 0; - * }, []); - * // => [4, 9] - * - * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } - */ - function transform(object, iteratee, accumulator) { - var isArr = isArray(object), - isArrLike = isArr || isBuffer(object) || isTypedArray(object); - - iteratee = getIteratee(iteratee, 4); - if (accumulator == null) { - var Ctor = object && object.constructor; - if (isArrLike) { - accumulator = isArr ? new Ctor : []; - } - else if (isObject(object)) { - accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; - } - else { - accumulator = {}; - } - } - (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { - return iteratee(accumulator, value, index, object); - }); - return accumulator; - } - - /** - * Removes the property at `path` of `object`. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 7 } }] }; - * _.unset(object, 'a[0].b.c'); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - * - * _.unset(object, ['a', '0', 'b', 'c']); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - */ - function unset(object, path) { - return object == null ? true : baseUnset(object, path); - } - - /** - * This method is like `_.set` except that accepts `updater` to produce the - * value to set. Use `_.updateWith` to customize `path` creation. The `updater` - * is invoked with one argument: (value). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.update(object, 'a[0].b.c', function(n) { return n * n; }); - * console.log(object.a[0].b.c); - * // => 9 - * - * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); - * console.log(object.x[0].y.z); - * // => 0 - */ - function update(object, path, updater) { - return object == null ? object : baseUpdate(object, path, castFunction(updater)); - } - - /** - * This method is like `_.update` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.updateWith(object, '[0][1]', _.constant('a'), Object); - * // => { '0': { '1': 'a' } } - */ - function updateWith(object, path, updater, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); - } - - /** - * Creates an array of the own enumerable string keyed property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return object == null ? [] : baseValues(object, keys(object)); - } - - /** - * Creates an array of the own and inherited enumerable string keyed property - * values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.valuesIn(new Foo); - * // => [1, 2, 3] (iteration order is not guaranteed) - */ - function valuesIn(object) { - return object == null ? [] : baseValues(object, keysIn(object)); - } - - /*------------------------------------------------------------------------*/ - - /** - * Clamps `number` within the inclusive `lower` and `upper` bounds. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Number - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - * @example - * - * _.clamp(-10, -5, 5); - * // => -5 - * - * _.clamp(10, -5, 5); - * // => 5 - */ - function clamp(number, lower, upper) { - if (upper === undefined) { - upper = lower; - lower = undefined; - } - if (upper !== undefined) { - upper = toNumber(upper); - upper = upper === upper ? upper : 0; - } - if (lower !== undefined) { - lower = toNumber(lower); - lower = lower === lower ? lower : 0; - } - return baseClamp(toNumber(number), lower, upper); - } - - /** - * Checks if `n` is between `start` and up to, but not including, `end`. If - * `end` is not specified, it's set to `start` with `start` then set to `0`. - * If `start` is greater than `end` the params are swapped to support - * negative ranges. - * - * @static - * @memberOf _ - * @since 3.3.0 - * @category Number - * @param {number} number The number to check. - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - * @see _.range, _.rangeRight - * @example - * - * _.inRange(3, 2, 4); - * // => true - * - * _.inRange(4, 8); - * // => true - * - * _.inRange(4, 2); - * // => false - * - * _.inRange(2, 2); - * // => false - * - * _.inRange(1.2, 2); - * // => true - * - * _.inRange(5.2, 4); - * // => false - * - * _.inRange(-3, -2, -6); - * // => true - */ - function inRange(number, start, end) { - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - number = toNumber(number); - return baseInRange(number, start, end); - } - - /** - * Produces a random number between the inclusive `lower` and `upper` bounds. - * If only one argument is provided a number between `0` and the given number - * is returned. If `floating` is `true`, or either `lower` or `upper` are - * floats, a floating-point number is returned instead of an integer. - * - * **Note:** JavaScript follows the IEEE-754 standard for resolving - * floating-point values which can produce unexpected results. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Number - * @param {number} [lower=0] The lower bound. - * @param {number} [upper=1] The upper bound. - * @param {boolean} [floating] Specify returning a floating-point number. - * @returns {number} Returns the random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(lower, upper, floating) { - if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { - upper = floating = undefined; - } - if (floating === undefined) { - if (typeof upper == 'boolean') { - floating = upper; - upper = undefined; - } - else if (typeof lower == 'boolean') { - floating = lower; - lower = undefined; - } - } - if (lower === undefined && upper === undefined) { - lower = 0; - upper = 1; - } - else { - lower = toFinite(lower); - if (upper === undefined) { - upper = lower; - lower = 0; - } else { - upper = toFinite(upper); - } - } - if (lower > upper) { - var temp = lower; - lower = upper; - upper = temp; - } - if (floating || lower % 1 || upper % 1) { - var rand = nativeRandom(); - return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); - } - return baseRandom(lower, upper); - } - - /*------------------------------------------------------------------------*/ - - /** - * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the camel cased string. - * @example - * - * _.camelCase('Foo Bar'); - * // => 'fooBar' - * - * _.camelCase('--foo-bar--'); - * // => 'fooBar' - * - * _.camelCase('__FOO_BAR__'); - * // => 'fooBar' - */ - var camelCase = createCompounder(function(result, word, index) { - word = word.toLowerCase(); - return result + (index ? capitalize(word) : word); - }); - - /** - * Converts the first character of `string` to upper case and the remaining - * to lower case. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to capitalize. - * @returns {string} Returns the capitalized string. - * @example - * - * _.capitalize('FRED'); - * // => 'Fred' - */ - function capitalize(string) { - return upperFirst(toString(string).toLowerCase()); - } - - /** - * Deburrs `string` by converting - * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) - * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) - * letters to basic Latin letters and removing - * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to deburr. - * @returns {string} Returns the deburred string. - * @example - * - * _.deburr('dÊjà vu'); - * // => 'deja vu' - */ - function deburr(string) { - string = toString(string); - return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); - } - - /** - * Checks if `string` ends with the given target string. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to inspect. - * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search up to. - * @returns {boolean} Returns `true` if `string` ends with `target`, - * else `false`. - * @example - * - * _.endsWith('abc', 'c'); - * // => true - * - * _.endsWith('abc', 'b'); - * // => false - * - * _.endsWith('abc', 'b', 2); - * // => true - */ - function endsWith(string, target, position) { - string = toString(string); - target = baseToString(target); - - var length = string.length; - position = position === undefined - ? length - : baseClamp(toInteger(position), 0, length); - - var end = position; - position -= target.length; - return position >= 0 && string.slice(position, end) == target; - } - - /** - * Converts the characters "&", "<", ">", '"', and "'" in `string` to their - * corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional - * characters use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. See - * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * When working with HTML you should always - * [quote attribute values](http://wonko.com/post/html-escaping) to reduce - * XSS vectors. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - string = toString(string); - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, escapeHtmlChar) - : string; - } - - /** - * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", - * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escapeRegExp('[lodash](https://lodash.com/)'); - * // => '\[lodash\]\(https://lodash\.com/\)' - */ - function escapeRegExp(string) { - string = toString(string); - return (string && reHasRegExpChar.test(string)) - ? string.replace(reRegExpChar, '\\$&') - : string; - } - - /** - * Converts `string` to - * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the kebab cased string. - * @example - * - * _.kebabCase('Foo Bar'); - * // => 'foo-bar' - * - * _.kebabCase('fooBar'); - * // => 'foo-bar' - * - * _.kebabCase('__FOO_BAR__'); - * // => 'foo-bar' - */ - var kebabCase = createCompounder(function(result, word, index) { - return result + (index ? '-' : '') + word.toLowerCase(); - }); - - /** - * Converts `string`, as space separated words, to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the lower cased string. - * @example - * - * _.lowerCase('--Foo-Bar--'); - * // => 'foo bar' - * - * _.lowerCase('fooBar'); - * // => 'foo bar' - * - * _.lowerCase('__FOO_BAR__'); - * // => 'foo bar' - */ - var lowerCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + word.toLowerCase(); - }); - - /** - * Converts the first character of `string` to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.lowerFirst('Fred'); - * // => 'fred' - * - * _.lowerFirst('FRED'); - * // => 'fRED' - */ - var lowerFirst = createCaseFirst('toLowerCase'); - - /** - * Pads `string` on the left and right sides if it's shorter than `length`. - * Padding characters are truncated if they can't be evenly divided by `length`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.pad('abc', 8); - * // => ' abc ' - * - * _.pad('abc', 8, '_-'); - * // => '_-abc_-_' - * - * _.pad('abc', 3); - * // => 'abc' - */ - function pad(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - if (!length || strLength >= length) { - return string; - } - var mid = (length - strLength) / 2; - return ( - createPadding(nativeFloor(mid), chars) + - string + - createPadding(nativeCeil(mid), chars) - ); - } - - /** - * Pads `string` on the right side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padEnd('abc', 6); - * // => 'abc ' - * - * _.padEnd('abc', 6, '_-'); - * // => 'abc_-_' - * - * _.padEnd('abc', 3); - * // => 'abc' - */ - function padEnd(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (string + createPadding(length - strLength, chars)) - : string; - } - - /** - * Pads `string` on the left side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padStart('abc', 6); - * // => ' abc' - * - * _.padStart('abc', 6, '_-'); - * // => '_-_abc' - * - * _.padStart('abc', 3); - * // => 'abc' - */ - function padStart(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (createPadding(length - strLength, chars) + string) - : string; - } - - /** - * Converts `string` to an integer of the specified radix. If `radix` is - * `undefined` or `0`, a `radix` of `10` is used unless `value` is a - * hexadecimal, in which case a `radix` of `16` is used. - * - * **Note:** This method aligns with the - * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category String - * @param {string} string The string to convert. - * @param {number} [radix=10] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {number} Returns the converted integer. - * @example - * - * _.parseInt('08'); - * // => 8 - * - * _.map(['6', '08', '10'], _.parseInt); - * // => [6, 8, 10] - */ - function parseInt(string, radix, guard) { - if (guard || radix == null) { - radix = 0; - } else if (radix) { - radix = +radix; - } - return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); - } - - /** - * Repeats the given string `n` times. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to repeat. - * @param {number} [n=1] The number of times to repeat the string. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {string} Returns the repeated string. - * @example - * - * _.repeat('*', 3); - * // => '***' - * - * _.repeat('abc', 2); - * // => 'abcabc' - * - * _.repeat('abc', 0); - * // => '' - */ - function repeat(string, n, guard) { - if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { - n = 1; - } else { - n = toInteger(n); - } - return baseRepeat(toString(string), n); - } - - /** - * Replaces matches for `pattern` in `string` with `replacement`. - * - * **Note:** This method is based on - * [`String#replace`](https://mdn.io/String/replace). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to modify. - * @param {RegExp|string} pattern The pattern to replace. - * @param {Function|string} replacement The match replacement. - * @returns {string} Returns the modified string. - * @example - * - * _.replace('Hi Fred', 'Fred', 'Barney'); - * // => 'Hi Barney' - */ - function replace() { - var args = arguments, - string = toString(args[0]); - - return args.length < 3 ? string : string.replace(args[1], args[2]); - } - - /** - * Converts `string` to - * [snake case](https://en.wikipedia.org/wiki/Snake_case). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the snake cased string. - * @example - * - * _.snakeCase('Foo Bar'); - * // => 'foo_bar' - * - * _.snakeCase('fooBar'); - * // => 'foo_bar' - * - * _.snakeCase('--FOO-BAR--'); - * // => 'foo_bar' - */ - var snakeCase = createCompounder(function(result, word, index) { - return result + (index ? '_' : '') + word.toLowerCase(); - }); - - /** - * Splits `string` by `separator`. - * - * **Note:** This method is based on - * [`String#split`](https://mdn.io/String/split). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to split. - * @param {RegExp|string} separator The separator pattern to split by. - * @param {number} [limit] The length to truncate results to. - * @returns {Array} Returns the string segments. - * @example - * - * _.split('a-b-c', '-', 2); - * // => ['a', 'b'] - */ - function split(string, separator, limit) { - if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { - separator = limit = undefined; - } - limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; - if (!limit) { - return []; - } - string = toString(string); - if (string && ( - typeof separator == 'string' || - (separator != null && !isRegExp(separator)) - )) { - separator = baseToString(separator); - if (!separator && hasUnicode(string)) { - return castSlice(stringToArray(string), 0, limit); - } - } - return string.split(separator, limit); - } - - /** - * Converts `string` to - * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). - * - * @static - * @memberOf _ - * @since 3.1.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the start cased string. - * @example - * - * _.startCase('--foo-bar--'); - * // => 'Foo Bar' - * - * _.startCase('fooBar'); - * // => 'Foo Bar' - * - * _.startCase('__FOO_BAR__'); - * // => 'FOO BAR' - */ - var startCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + upperFirst(word); - }); - - /** - * Checks if `string` starts with the given target string. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to inspect. - * @param {string} [target] The string to search for. - * @param {number} [position=0] The position to search from. - * @returns {boolean} Returns `true` if `string` starts with `target`, - * else `false`. - * @example - * - * _.startsWith('abc', 'a'); - * // => true - * - * _.startsWith('abc', 'b'); - * // => false - * - * _.startsWith('abc', 'b', 1); - * // => true - */ - function startsWith(string, target, position) { - string = toString(string); - position = position == null - ? 0 - : baseClamp(toInteger(position), 0, string.length); - - target = baseToString(target); - return string.slice(position, position + target.length) == target; - } - - /** - * Creates a compiled template function that can interpolate data properties - * in "interpolate" delimiters, HTML-escape interpolated data properties in - * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data - * properties may be accessed as free variables in the template. If a setting - * object is given, it takes precedence over `_.templateSettings` values. - * - * **Note:** In the development build `_.template` utilizes - * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) - * for easier debugging. - * - * For more information on precompiling templates see - * [lodash's custom builds documentation](https://lodash.com/custom-builds). - * - * For more information on Chrome extension sandboxes see - * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The template string. - * @param {Object} [options={}] The options object. - * @param {RegExp} [options.escape=_.templateSettings.escape] - * The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] - * The "evaluate" delimiter. - * @param {Object} [options.imports=_.templateSettings.imports] - * An object to import into the template as free variables. - * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] - * The "interpolate" delimiter. - * @param {string} [options.sourceURL='lodash.templateSources[n]'] - * The sourceURL of the compiled template. - * @param {string} [options.variable='obj'] - * The data object variable name. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the compiled template function. - * @example - * - * // Use the "interpolate" delimiter to create a compiled template. - * var compiled = _.template('hello <%= user %>!'); - * compiled({ 'user': 'fred' }); - * // => 'hello fred!' - * - * // Use the HTML "escape" delimiter to escape data property values. - * var compiled = _.template('<%- value %>'); - * compiled({ 'value': ' diff --git a/packages/services/examples/browser-require/main.py b/packages/services/examples/browser-require/main.py new file mode 100644 index 000000000000..6b42d85aef9a --- /dev/null +++ b/packages/services/examples/browser-require/main.py @@ -0,0 +1,65 @@ +""" +Copyright (c) Jupyter Development Team. +Distributed under the terms of the Modified BSD License. +""" +import os +import os.path as osp + +from jupyter_server.base.handlers import JupyterHandler +from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin, ExtensionHandlerMixin +from jupyter_server.utils import url_path_join as ujoin +from jupyterlab_server import LabServerApp + +HERE = osp.dirname(__file__) + + +def _jupyter_server_extension_points(): + return [{"module": __name__, "app": ExampleApp}] + + +class ExampleHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): + """Handle requests between the main app page and notebook server.""" + + def get(self): + """Get the main page for the application's interface.""" + config_data = { + # Use camelCase here, since that's what the lab components expect + "baseUrl": self.base_url, + "token": self.settings["token"], + "fullStaticUrl": ujoin(self.base_url, "static", self.name), + "frontendUrl": ujoin(self.base_url, "example/"), + } + return self.write( + self.render_template( + "index.html", + static=self.static_url, + base_url=self.base_url, + token=self.settings["token"], + page_config=config_data, + ) + ) + + +class ExampleApp(LabServerApp): + extension_url = "/example" + app_url = "/example" + default_url = "/example" + name = __name__ + # In jupyter-server v2 terminals are an extension + load_other_extensions = True + app_name = "JupyterLab Example Service" + static_dir = os.path.join(HERE, "static") + templates_dir = os.path.join(HERE) + app_settings_dir = os.path.join(HERE, "build", "application_settings") + schemas_dir = os.path.join(HERE, "build", "schemas") + themes_dir = os.path.join(HERE, "build", "themes") + user_settings_dir = os.path.join(HERE, "build", "user_settings") + workspaces_dir = os.path.join(HERE, "build", "workspaces") + + def initialize_handlers(self): + """Add example handler to Lab Server's handler list.""" + self.handlers.append(("/example", ExampleHandler)) + + +if __name__ == "__main__": + ExampleApp.launch_instance() diff --git a/packages/services/examples/browser-require/static/index.js b/packages/services/examples/browser-require/static/index.js index 3fecb25c3a85..7ad22c40ee74 100644 --- a/packages/services/examples/browser-require/static/index.js +++ b/packages/services/examples/browser-require/static/index.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + require(['jquery', '@jupyterlab/services'], function($, services) { /* eslint-disable no-console */ console.log('Starting example'); @@ -10,12 +15,20 @@ require(['jquery', '@jupyterlab/services'], function($, services) { // start a single kernel for the page kernelManager.startNew(kernelOptions).then(function(kernel) { console.log('Kernel started:', kernel); - kernel.requestKernelInfo().then(function(reply) { - const content = reply.content; - $('#kernel-info').text(content.banner); - console.log('Kernel info:', content); - console.log('Example started!'); - }); + const waitForIdle = (_, status) => { + if( status === 'idle' ) { + kernel.statusChanged.disconnect(waitForIdle) + kernel.requestKernelInfo().then(function(reply) { + const content = reply.content; + $('#kernel-info').text(content.banner); + console.log('Kernel info:', content); + console.log('Example started!'); + }); + } + }; + + kernel.statusChanged.connect(waitForIdle); + $('#run').click(function() { const code = $('#cell').val(); console.log('Executing:', code); diff --git a/packages/services/examples/browser/main.py b/packages/services/examples/browser/main.py index 57fd7fb92f37..d37efa58e19a 100644 --- a/packages/services/examples/browser/main.py +++ b/packages/services/examples/browser/main.py @@ -6,14 +6,10 @@ import os import os.path as osp -from jupyter_server.base.handlers import FileFindHandler, JupyterHandler -from jupyter_server.extension.handler import ( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, -) +from jupyter_server.base.handlers import JupyterHandler +from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin, ExtensionHandlerMixin from jupyter_server.utils import url_path_join as ujoin -from jupyterlab_server import LabConfig, LabServerApp -from traitlets import Unicode +from jupyterlab_server import LabServerApp HERE = osp.dirname(__file__) @@ -50,7 +46,6 @@ def get(self): class ExampleApp(LabServerApp): - extension_url = "/example" default_url = "/example" app_url = "/example" diff --git a/packages/services/examples/browser/package.json b/packages/services/examples/browser/package.json index a7efcff9520c..1b2fc42ab11e 100644 --- a/packages/services/examples/browser/package.json +++ b/packages/services/examples/browser/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/example-services-browser", - "version": "3.6.6", + "version": "4.0.8", "private": true, "files": [ "lib/*.{d.ts,js,js.map}" @@ -10,14 +10,14 @@ "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo" }, "dependencies": { - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/services": "^6.6.6", - "@lumino/coreutils": "^1.11.0" + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/services": "^7.0.8", + "@lumino/coreutils": "^2.1.2" }, "devDependencies": { "rimraf": "~3.0.0", - "typescript": "~4.1.3", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0" + "typescript": "~5.0.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1" } } diff --git a/packages/services/examples/browser/src/comm.ts b/packages/services/examples/browser/src/comm.ts index a32a947b8a20..06ca2be6ce3a 100644 --- a/packages/services/examples/browser/src/comm.ts +++ b/packages/services/examples/browser/src/comm.ts @@ -6,7 +6,7 @@ import { PromiseDelegate } from '@lumino/coreutils'; import { log } from './log'; -export async function main() { +export async function main(): Promise { // Start a python kernel const kernelManager = new KernelManager(); const kernel = await kernelManager.startNew({ name: 'python' }); diff --git a/packages/services/examples/browser/src/config.ts b/packages/services/examples/browser/src/config.ts index 089cf9520385..ed02c0dc28a3 100644 --- a/packages/services/examples/browser/src/config.ts +++ b/packages/services/examples/browser/src/config.ts @@ -5,7 +5,7 @@ import { ConfigSection, ConfigWithDefaults } from '@jupyterlab/services'; import { log } from './log'; -export async function main() { +export async function main(): Promise { log('Config'); // The base url of the Jupyter server. diff --git a/packages/services/examples/browser/src/contents.ts b/packages/services/examples/browser/src/contents.ts index 2804fee6ef33..2fecba6b49a9 100644 --- a/packages/services/examples/browser/src/contents.ts +++ b/packages/services/examples/browser/src/contents.ts @@ -5,7 +5,7 @@ import { ContentsManager } from '@jupyterlab/services'; import { log } from './log'; -export async function main() { +export async function main(): Promise { const contents = new ContentsManager(); log('Create a new directory'); diff --git a/packages/services/examples/browser/src/kernel.ts b/packages/services/examples/browser/src/kernel.ts index 94a0a67a5d6a..e5f30d9e25ec 100644 --- a/packages/services/examples/browser/src/kernel.ts +++ b/packages/services/examples/browser/src/kernel.ts @@ -5,7 +5,7 @@ import { KernelAPI, KernelManager, KernelMessage } from '@jupyterlab/services'; import { log } from './log'; -export async function main() { +export async function main(): Promise { // Start a python kernel const kernelManager = new KernelManager(); const kernel = await kernelManager.startNew({ name: 'python' }); diff --git a/packages/services/examples/browser/src/kernelspec.ts b/packages/services/examples/browser/src/kernelspec.ts index b69969779c0b..54c6cba9884d 100644 --- a/packages/services/examples/browser/src/kernelspec.ts +++ b/packages/services/examples/browser/src/kernelspec.ts @@ -5,7 +5,7 @@ import { KernelSpecManager } from '@jupyterlab/services'; import { log } from './log'; -export async function main() { +export async function main(): Promise { log('Get the list of kernel specs'); const kernelSpecManager = new KernelSpecManager(); await kernelSpecManager.ready; diff --git a/packages/services/examples/browser/src/log.ts b/packages/services/examples/browser/src/log.ts index 7c45470a74b5..8cb6000bad0f 100644 --- a/packages/services/examples/browser/src/log.ts +++ b/packages/services/examples/browser/src/log.ts @@ -1,6 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function log(content: any): void { const el = document.getElementById('output'); if (typeof content !== 'string') { diff --git a/packages/services/examples/browser/src/session.ts b/packages/services/examples/browser/src/session.ts index 854b073fdd0e..332d038ff0e3 100644 --- a/packages/services/examples/browser/src/session.ts +++ b/packages/services/examples/browser/src/session.ts @@ -10,7 +10,7 @@ import { import { log } from './log'; -export async function main() { +export async function main(): Promise { log('Starting session manager'); const kernelManager = new KernelManager(); const sessionManager = new SessionManager({ kernelManager }); diff --git a/packages/services/examples/browser/src/terminal.ts b/packages/services/examples/browser/src/terminal.ts index c0869a5e5521..ef07e230663b 100644 --- a/packages/services/examples/browser/src/terminal.ts +++ b/packages/services/examples/browser/src/terminal.ts @@ -5,7 +5,7 @@ import { Terminal, TerminalManager } from '@jupyterlab/services'; import { log } from './log'; -export async function main() { +export async function main(): Promise { log('Terminal'); // See if terminals are available diff --git a/packages/services/examples/browser/templates/index.html b/packages/services/examples/browser/templates/index.html index 76dff19fe6fb..2ab4d4d8d82e 100644 --- a/packages/services/examples/browser/templates/index.html +++ b/packages/services/examples/browser/templates/index.html @@ -1,3 +1,8 @@ + + diff --git a/packages/services/examples/browser/webpack.config.js b/packages/services/examples/browser/webpack.config.js index 17979e8bfbe5..c793fbbdfe5d 100644 --- a/packages/services/examples/browser/webpack.config.js +++ b/packages/services/examples/browser/webpack.config.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const webpack = require('webpack'); const crypto = require('crypto'); @@ -16,10 +21,8 @@ module.exports = { }, plugins: [ new webpack.DefinePlugin({ - // Needed for Blueprint. See https://github.com/palantir/blueprint/issues/4393 - 'process.env': '{}', // Needed for various packages using cwd(), like the path polyfill - process: { cwd: () => '/' } + process: { cwd: () => '/', env: {} } }) ], bail: true diff --git a/packages/services/examples/node/main.py b/packages/services/examples/node/main.py index 79547904c009..b66a2a89e183 100644 --- a/packages/services/examples/node/main.py +++ b/packages/services/examples/node/main.py @@ -1,8 +1,6 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from __future__ import absolute_import, print_function - import json import os.path as osp @@ -17,23 +15,24 @@ def _jupyter_server_extension_points(): class NodeApp(ProcessApp): - name = __name__ - serverapp_config = dict(allow_origin="*") + serverapp_config = {"allow_origin": "*"} def get_command(self): """Get the command and kwargs to run.""" # Run the node script with command arguments. - config = dict( - baseUrl="http://localhost:{}{}".format(self.serverapp.port, self.settings["base_url"]), - token=self.settings["token"], - ) + config = { + "baseUrl": "http://localhost:{}{}".format( + self.serverapp.port, self.settings["base_url"] + ), + "token": self.settings["token"], + } with open(osp.join(HERE, "config.json"), "w") as fid: json.dump(config, fid) cmd = [which("node"), "index.js", "--jupyter-config-data=./config.json"] - return cmd, dict(cwd=HERE) + return cmd, {"cwd": HERE} if __name__ == "__main__": diff --git a/packages/services/examples/node/package.json b/packages/services/examples/node/package.json index 934c504549f1..b41b10666282 100644 --- a/packages/services/examples/node/package.json +++ b/packages/services/examples/node/package.json @@ -1,15 +1,14 @@ { "name": "node-example", - "version": "3.6.6", + "version": "4.0.8", "private": true, "scripts": { "clean": "rimraf node_modules", "update": "rimraf node_modules/@jupyterlab/services && npm install" }, "dependencies": { - "@jupyterlab/services": "^6.6.6", - "node-fetch": "^2.6.0", - "ws": "^7.4.6" + "@jupyterlab/services": "^7.0.8", + "ws": "^8.11.0" }, "devDependencies": { "rimraf": "~3.0.0" diff --git a/packages/services/examples/node/templates/index.html b/packages/services/examples/node/templates/index.html index f1af9ec555f7..11d8f23ef7a2 100644 --- a/packages/services/examples/node/templates/index.html +++ b/packages/services/examples/node/templates/index.html @@ -1,13 +1,18 @@ + + {{page_config['appName'] | e}} {# Copy so we do not modify the page_config with updates. #} {% set page_config_full = page_config.copy() %} - + {# Set a dummy variable - we just want the side effect of the update. #} {% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} - + diff --git a/packages/services/examples/typescript-browser-with-output/main.py b/packages/services/examples/typescript-browser-with-output/main.py index 1bebf29b5aad..dab0481c8918 100644 --- a/packages/services/examples/typescript-browser-with-output/main.py +++ b/packages/services/examples/typescript-browser-with-output/main.py @@ -6,14 +6,10 @@ import os import os.path as osp -from jupyter_server.base.handlers import FileFindHandler, JupyterHandler -from jupyter_server.extension.handler import ( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, -) +from jupyter_server.base.handlers import JupyterHandler +from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin, ExtensionHandlerMixin from jupyter_server.utils import url_path_join as ujoin -from jupyterlab_server import LabConfig, LabServerApp -from traitlets import Unicode +from jupyterlab_server import LabServerApp HERE = osp.dirname(__file__) @@ -50,7 +46,6 @@ def get(self): class ExampleApp(LabServerApp): - extension_url = "/example" app_url = "/example" default_url = "/example" diff --git a/packages/services/examples/typescript-browser-with-output/package.json b/packages/services/examples/typescript-browser-with-output/package.json index 418ebfa7e7e6..f55faaf70a7a 100644 --- a/packages/services/examples/typescript-browser-with-output/package.json +++ b/packages/services/examples/typescript-browser-with-output/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/example-services-outputarea", - "version": "3.6.6", + "version": "4.0.8", "private": true, "sideEffects": [ "style/*" @@ -16,18 +16,18 @@ "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo" }, "dependencies": { - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/outputarea": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/services": "^6.6.6" + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/outputarea": "^4.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/services": "^7.0.8" }, "devDependencies": { - "css-loader": "^5.0.1", + "css-loader": "^6.7.1", "rimraf": "~3.0.0", - "style-loader": "~2.0.0", - "typescript": "~4.1.3", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0" + "style-loader": "~3.3.1", + "typescript": "~5.0.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1" }, "styleModule": "style/index.js" } diff --git a/packages/services/examples/typescript-browser-with-output/templates/index.html b/packages/services/examples/typescript-browser-with-output/templates/index.html index e785f9953b91..a101550fa9b3 100644 --- a/packages/services/examples/typescript-browser-with-output/templates/index.html +++ b/packages/services/examples/typescript-browser-with-output/templates/index.html @@ -1,3 +1,8 @@ + + diff --git a/packages/services/examples/typescript-browser-with-output/webpack.config.js b/packages/services/examples/typescript-browser-with-output/webpack.config.js index c259fd577a9a..684c91fa6a44 100644 --- a/packages/services/examples/typescript-browser-with-output/webpack.config.js +++ b/packages/services/examples/typescript-browser-with-output/webpack.config.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const path = require('path'); const webpack = require('webpack'); const crypto = require('crypto'); @@ -18,8 +23,8 @@ module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - { test: /\.md$/, use: 'raw-loader' }, - { test: /\.txt$/, use: 'raw-loader' }, + { test: /\.md$/, type: 'asset/source' }, + { test: /\.txt$/, type: 'asset/source' }, { test: /\.js$/, use: ['source-map-loader'], @@ -27,38 +32,36 @@ module.exports = { // eslint-disable-next-line no-undef exclude: /node_modules/ }, - { test: /\.(jpg|png|gif)$/, use: 'file-loader' }, - { test: /\.js.map$/, use: 'file-loader' }, + { test: /\.(jpg|png|gif)$/, type: 'asset/resource' }, + { test: /\.js.map$/, type: 'asset/resource' }, { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/font-woff' + type: 'asset' }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/font-woff' + type: 'asset' }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/octet-stream' + type: 'asset' }, { test: /\.otf(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/octet-stream' + type: 'asset' }, - { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, use: 'file-loader' }, + { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, type: 'asset/resource' }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=image/svg+xml' + type: 'asset' } ] }, bail: true, plugins: [ new webpack.DefinePlugin({ - // Needed for Blueprint. See https://github.com/palantir/blueprint/issues/4393 - 'process.env': '{}', // Needed for various packages using cwd(), like the path polyfill - process: { cwd: () => '/' } + process: { cwd: () => '/', env: {} } }) ] }; diff --git a/packages/services/jest.config.js b/packages/services/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/services/jest.config.js +++ b/packages/services/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/services/package.json b/packages/services/package.json index 3b54fa40ef18..a822c6f75929 100644 --- a/packages/services/package.json +++ b/packages/services/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/services", - "version": "6.6.6", + "version": "7.0.8", "description": "Client APIs for the Jupyter services REST APIs", "keywords": [ "jupyter", @@ -19,7 +19,6 @@ "author": "Project Jupyter", "main": "lib/index.js", "browser": { - "node-fetch": false, "ws": "./lib/shim/ws.js" }, "typings": "lib/index.d.ts", @@ -31,7 +30,8 @@ "lib/*.js", "lib/*.d.ts", "dist/*.js", - "dist/**/*.js" + "dist/**/*.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -39,40 +39,35 @@ "build:test": "tsc --build tsconfig.test.json", "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", "docs": "typedoc src", - "test": "jest", - "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test": "jest -i", + "test:cov": "jest -i --collect-coverage", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/nbformat": "^3.6.6", - "@jupyterlab/observables": "^4.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/statedb": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/polling": "^1.9.0", - "@lumino/signaling": "^1.10.0", - "node-fetch": "^2.6.0", - "ws": "^7.4.6" + "@jupyter/ydoc": "^1.0.2", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/nbformat": "^4.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@jupyterlab/statedb": "^4.0.8", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/polling": "^2.1.2", + "@lumino/properties": "^2.0.1", + "@lumino/signaling": "^2.1.2", + "ws": "^8.11.0" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "@types/node-fetch": "^2.5.4", - "@types/text-encoding": "^0.0.35", - "@types/ws": "^7.4.4", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "@types/ws": "^8.5.3", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "text-encoding": "^0.7.0", - "ts-jest": "^26.3.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3", - "webpack": "^5.41.1", - "webpack-cli": "^4.1.0" + "typedoc": "~0.24.7", + "typescript": "~5.0.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1" }, "publishConfig": { "access": "public" diff --git a/packages/services/src/basemanager.ts b/packages/services/src/basemanager.ts index d3f1d479a672..1438d2fc1692 100644 --- a/packages/services/src/basemanager.ts +++ b/packages/services/src/basemanager.ts @@ -31,6 +31,11 @@ export interface IManager extends IObservableDisposable { * A promise that resolves when the manager is initially ready. */ readonly ready: Promise; + + /** + * Whether the manager is active. + */ + readonly isActive: boolean; } export abstract class BaseManager implements IManager { @@ -67,6 +72,13 @@ export abstract class BaseManager implements IManager { */ abstract ready: Promise; + /** + * Whether the manager is active. + */ + get isActive(): boolean { + return true; + } + /** * Dispose of the delegate and invoke the callback function. */ diff --git a/packages/services/src/config/index.ts b/packages/services/src/config/index.ts index 8e28c761cbd7..176f4d601bfa 100644 --- a/packages/services/src/config/index.ts +++ b/packages/services/src/config/index.ts @@ -104,7 +104,7 @@ class DefaultConfigSection implements IConfigSection { * Load the initial data for this section. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/config). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/config). * * The promise is fulfilled on a valid response and rejected otherwise. */ @@ -125,7 +125,7 @@ class DefaultConfigSection implements IConfigSection { * Modify the stored config values. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/config). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/config). * * The promise is fulfilled on a valid response and rejected otherwise. * @@ -181,7 +181,7 @@ export class ConfigWithDefaults { * Set a config value. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/config). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/config). * * The promise is fulfilled on a valid response and rejected otherwise. * diff --git a/packages/services/src/contents/index.ts b/packages/services/src/contents/index.ts index a5535b25a75c..4e68ff5fb94a 100644 --- a/packages/services/src/contents/index.ts +++ b/packages/services/src/contents/index.ts @@ -1,14 +1,12 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { PathExt, URLExt } from '@jupyterlab/coreutils'; +import type { ISharedDocument } from '@jupyter/ydoc'; -import { ModelDB } from '@jupyterlab/observables'; +import { PathExt, URLExt } from '@jupyterlab/coreutils'; import { PartialJSONObject } from '@lumino/coreutils'; -import { each } from '@lumino/algorithm'; - import { IDisposable } from '@lumino/disposable'; import { ISignal, Signal } from '@lumino/signaling'; @@ -222,6 +220,49 @@ export namespace Contents { newValue: Partial | null; } + /** + * A factory interface for creating `ISharedDocument` objects. + */ + export interface ISharedFactory { + /** + * Whether the IDrive supports real-time collaboration or not. + * Note: If it is not provided, it is false by default. + */ + readonly collaborative?: boolean; + + /** + * Create a new `ISharedDocument` instance. + * + * It should return `undefined` if the factory is not able to create a `ISharedDocument`. + */ + createNew(options: ISharedFactoryOptions): ISharedDocument | undefined; + } + + /** + * The options used to instantiate a ISharedDocument + */ + export interface ISharedFactoryOptions { + /** + * The path of the file. + */ + path: string; + /** + * The format of the document. If null, the document won't be + * collaborative. + */ + format: FileFormat; + /** + * The content type of the document. + */ + contentType: ContentType; + /** + * Wether the document is collaborative or not. + * + * The default value is `true`. + */ + collaborative?: boolean; + } + /** * The interface for a contents manager. */ @@ -287,11 +328,11 @@ export namespace Contents { driveName(path: string): string; /** - * Given a path, get a ModelDB.IFactory from the + * Given a path, get a shared model IFactory from the * relevant backend. Returns `null` if the backend * does not provide one. */ - getModelDBFactory(path: string): ModelDB.IFactory | null; + getSharedModelFactory(path: string): ISharedFactory | null; /** * Get a file or directory. @@ -430,10 +471,10 @@ export namespace Contents { readonly serverSettings: ServerConnection.ISettings; /** - * An optional ModelDB.IFactory instance for the + * An optional shared model factory instance for the * drive. */ - readonly modelDBFactory?: ModelDB.IFactory; + readonly sharedModelFactory?: ISharedFactory; /** * A signal emitted when a file operation takes place. @@ -454,7 +495,7 @@ export namespace Contents { /** * Get an encoded download url given a file path. * - * @param A promise which resolves with the absolute POSIX + * @returns A promise which resolves with the absolute POSIX * file path on the server. * * #### Notes @@ -621,13 +662,13 @@ export class ContentsManager implements Contents.IManager { } /** - * Given a path, get a ModelDB.IFactory from the - * relevant backend. Returns `undefined` if the backend + * Given a path, get a shared model factory from the + * relevant backend. Returns `null` if the backend * does not provide one. */ - getModelDBFactory(path: string): ModelDB.IFactory | null { + getSharedModelFactory(path: string): Contents.ISharedFactory | null { const [drive] = this._driveForPath(path); - return drive?.modelDBFactory ?? null; + return drive?.sharedModelFactory ?? null; } /** @@ -720,12 +761,9 @@ export class ContentsManager implements Contents.IManager { return drive.get(localPath, options).then(contentsModel => { const listing: Contents.IModel[] = []; if (contentsModel.type === 'directory' && contentsModel.content) { - each(contentsModel.content, (item: Contents.IModel) => { - listing.push({ - ...item, - path: this._toGlobalPath(drive, item.path) - } as Contents.IModel); - }); + for (const item of contentsModel.content) { + listing.push({ ...item, path: this._toGlobalPath(drive, item.path) }); + } return { ...contentsModel, path: this._toGlobalPath(drive, localPath), @@ -1071,7 +1109,7 @@ export class Drive implements Contents.IDrive { * * @returns A promise which resolves with the file content. * - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents) and validates the response model. */ async get( localPath: string, @@ -1130,7 +1168,7 @@ export class Drive implements Contents.IDrive { * file is created. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents) and validates the response model. */ async newUntitled( options: Contents.ICreateOptions = {} @@ -1172,7 +1210,7 @@ export class Drive implements Contents.IDrive { * @returns A promise which resolves when the file is deleted. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents). */ async delete(localPath: string): Promise { const url = this._getUrl(localPath); @@ -1203,7 +1241,7 @@ export class Drive implements Contents.IDrive { * the file is renamed. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents) and validates the response model. */ async rename( oldLocalPath: string, @@ -1243,7 +1281,7 @@ export class Drive implements Contents.IDrive { * #### Notes * Ensure that `model.content` is populated for the file. * - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents) and validates the response model. */ async save( localPath: string, @@ -1284,7 +1322,7 @@ export class Drive implements Contents.IDrive { * #### Notes * The server will select the name of the copied file. * - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents) and validates the response model. */ async copy(fromFile: string, toDir: string): Promise { const settings = this.serverSettings; @@ -1317,7 +1355,7 @@ export class Drive implements Contents.IDrive { * checkpoint is created. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents) and validates the response model. */ async createCheckpoint( localPath: string @@ -1347,7 +1385,7 @@ export class Drive implements Contents.IDrive { * the file. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents) and validates the response model. */ async listCheckpoints( localPath: string @@ -1382,7 +1420,7 @@ export class Drive implements Contents.IDrive { * @returns A promise which resolves when the checkpoint is restored. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents). */ async restoreCheckpoint( localPath: string, @@ -1411,7 +1449,7 @@ export class Drive implements Contents.IDrive { * @returns A promise which resolves when the checkpoint is deleted. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents). */ async deleteCheckpoint( localPath: string, @@ -1486,7 +1524,7 @@ export namespace Drive { /** * A REST endpoint for drive requests. * If not given, defaults to the Jupyter - * REST API given by [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/contents). + * REST API given by [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/contents). */ apiEndpoint?: string; } diff --git a/packages/services/src/event/index.ts b/packages/services/src/event/index.ts index 2ceccfa09731..ddba24bdf784 100644 --- a/packages/services/src/event/index.ts +++ b/packages/services/src/event/index.ts @@ -1,11 +1,11 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { PageConfig, URLExt } from '@jupyterlab/coreutils'; -import { PromiseDelegate } from '@lumino/coreutils'; +import { URLExt } from '@jupyterlab/coreutils'; +import { JSONObject, ReadonlyJSONObject } from '@lumino/coreutils'; import { IDisposable } from '@lumino/disposable'; import { Poll } from '@lumino/polling'; -import { ISignal, Signal } from '@lumino/signaling'; +import { IStream, Signal, Stream } from '@lumino/signaling'; import { ServerConnection } from '../serverconnection'; /** @@ -16,7 +16,7 @@ const SERVICE_EVENTS_URL = 'api/events'; /** * The events API service manager. */ -export class EventManager implements IDisposable { +export class EventManager implements Event.IManager { /** * Create a new event manager. */ @@ -24,15 +24,12 @@ export class EventManager implements IDisposable { this.serverSettings = options.serverSettings ?? ServerConnection.makeSettings(); + // If subscription fails, the poll attempts to reconnect and backs off. this._poll = new Poll({ factory: () => this._subscribe() }); - this._stream = new Private.Stream(this); + this._stream = new Stream(this); - // TODO: Remove this logic in JupyterLab 4 - if (this._isDisabled) { - this._stream.stop(); - } else { - void this._poll.start(); - } + // Subscribe to the events socket. + void this._poll.start(); } /** @@ -44,7 +41,7 @@ export class EventManager implements IDisposable { * Whether the event manager is disposed. */ get isDisposed(): boolean { - return this._isDisposed; + return this._poll.isDisposed; } /** @@ -61,7 +58,6 @@ export class EventManager implements IDisposable { if (this.isDisposed) { return; } - this._isDisposed = true; // Clean up poll. this._poll.dispose(); @@ -105,7 +101,7 @@ export class EventManager implements IDisposable { */ private _subscribe(): Promise { return new Promise((_, reject) => { - if (this.isDisposed || this._isDisabled) { + if (this.isDisposed) { return; } @@ -116,19 +112,14 @@ export class EventManager implements IDisposable { const socket = (this._socket = new WebSocket(url)); const stream = this._stream; - // Cause the poll to tick a rejection and back off if the socket closes. socket.onclose = () => reject(new Error('EventManager socket closed')); socket.onmessage = msg => msg.data && stream.emit(JSON.parse(msg.data)); }); } - // TODO: Remove this check for the `jupyter_server` version. - // It is only necessary in JupyterLab < 4. - private _isDisabled = 2 > PageConfig.getNotebookVersion()[0]; - private _isDisposed = false; private _poll: Poll; private _socket: WebSocket | null = null; - private _stream: Private.Stream; + private _stream: Stream; } /** @@ -153,8 +144,7 @@ export namespace Event { /** * The event emission type. */ - export type Emission = { - [key: string]: any; + export type Emission = ReadonlyJSONObject & { schema_id: string; }; @@ -162,7 +152,7 @@ export namespace Event { * The event request type. */ export type Request = { - data: { [key: string]: any }; + data: JSONObject; schema_id: string; version: string; }; @@ -175,63 +165,18 @@ export namespace Event { /** * The interface for the event bus front-end. */ - export interface IManager extends EventManager {} - - /** - * An object that is both a signal and an async iterable. - */ - export interface IStream extends ISignal, AsyncIterable {} -} - -/** - * A namespace for private module data. - */ -namespace Private { - /** - * A pending promise in a promise chain underlying a stream. - */ - export type Pending = PromiseDelegate<{ args: U; next: Pending }>; - - /** - * A stream with the characteristics of a signal and an async iterable. - */ - export class Stream extends Signal { + export interface IManager extends IDisposable { /** - * Return an async iterator that yields every emission. + * The server settings used to make API requests. */ - async *[Symbol.asyncIterator](): AsyncIterableIterator { - let pending = this._pending; - while (true) { - try { - const { args, next } = await pending.promise; - pending = next; - yield args; - } catch (_) { - return; // Any promise rejection stops the iterator. - } - } - } - + readonly serverSettings: ServerConnection.ISettings; /** - * Emit the signal, invoke the connected slots, and yield the emission. - * - * @param args - The args to pass to the connected slots. + * An event stream that emits and yields each new event. */ - emit(args: U): void { - const pending = this._pending; - this._pending = new PromiseDelegate(); - pending.resolve({ args, next: this._pending }); - super.emit(args); - } - + readonly stream: Event.Stream; /** - * Stop the stream's async iteration. + * Post an event request to be emitted by the event bus. */ - stop(): void { - this._pending.promise.catch(() => undefined); - this._pending.reject('stop'); - } - - private _pending: Private.Pending = new PromiseDelegate(); + emit(event: Event.Request): Promise; } } diff --git a/packages/services/src/kernel/default.ts b/packages/services/src/kernel/default.ts index df8b2c81bc5d..65b9f6587139 100644 --- a/packages/services/src/kernel/default.ts +++ b/packages/services/src/kernel/default.ts @@ -21,7 +21,7 @@ import { KernelShellFutureHandler } from './future'; -import * as serialize from './serialize'; +import { deserialize, serialize } from './serialize'; import * as validate from './validate'; import { KernelSpec, KernelSpecAPI } from '../kernelspec'; @@ -407,7 +407,7 @@ export class KernelConnection implements Kernel.IKernelConnection { KernelMessage.isInfoRequestMsg(msg) ) { if (this.connectionStatus === 'connected') { - this._ws!.send(serialize.serialize(msg)); + this._ws!.send(serialize(msg, this._ws!.protocol)); return; } else { throw new Error('Could not send message: status is not connected'); @@ -425,7 +425,7 @@ export class KernelConnection implements Kernel.IKernelConnection { this.connectionStatus === 'connected' && this._kernelSession !== RESTARTING_KERNEL_SESSION ) { - this._ws!.send(serialize.serialize(msg)); + this._ws!.send(serialize(msg, this._ws!.protocol)); } else if (queue) { this._pendingMessages.push(msg); } else { @@ -437,7 +437,7 @@ export class KernelConnection implements Kernel.IKernelConnection { * Interrupt a kernel. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels). * * The promise is fulfilled on a valid response and rejected otherwise. * @@ -458,7 +458,7 @@ export class KernelConnection implements Kernel.IKernelConnection { * Request a kernel restart. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels) + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels) * and validates the response model. * * Any existing Future or Comm objects are cleared once the kernel has @@ -526,7 +526,7 @@ export class KernelConnection implements Kernel.IKernelConnection { * Shutdown a kernel. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels). * * The promise is fulfilled on a valid response and rejected otherwise. * @@ -629,9 +629,10 @@ export class KernelConnection implements Kernel.IKernelConnection { session: this._clientId, content }); - return Private.handleShellMessage(this, msg) as Promise< - KernelMessage.ICompleteReplyMsg - >; + return Private.handleShellMessage( + this, + msg + ) as Promise; } /** @@ -653,9 +654,10 @@ export class KernelConnection implements Kernel.IKernelConnection { session: this._clientId, content: content }); - return Private.handleShellMessage(this, msg) as Promise< - KernelMessage.IInspectReplyMsg - >; + return Private.handleShellMessage( + this, + msg + ) as Promise; } /** @@ -677,9 +679,10 @@ export class KernelConnection implements Kernel.IKernelConnection { session: this._clientId, content }); - return Private.handleShellMessage(this, msg) as Promise< - KernelMessage.IHistoryReplyMsg - >; + return Private.handleShellMessage( + this, + msg + ) as Promise; } /** @@ -783,9 +786,10 @@ export class KernelConnection implements Kernel.IKernelConnection { session: this._clientId, content }); - return Private.handleShellMessage(this, msg) as Promise< - KernelMessage.IIsCompleteReplyMsg - >; + return Private.handleShellMessage( + this, + msg + ) as Promise; } /** @@ -805,9 +809,10 @@ export class KernelConnection implements Kernel.IKernelConnection { session: this._clientId, content }); - return Private.handleShellMessage(this, msg) as Promise< - KernelMessage.ICommInfoReplyMsg - >; + return Private.handleShellMessage( + this, + msg + ) as Promise; } /** @@ -818,7 +823,7 @@ export class KernelConnection implements Kernel.IKernelConnection { */ sendInputReply( content: KernelMessage.IInputReplyMsg['content'], - parent_header?: KernelMessage.IInputReplyMsg['parent_header'] + parent_header: KernelMessage.IInputReplyMsg['parent_header'] ): void { const msg = KernelMessage.createMessage({ msgType: 'input_reply', @@ -827,9 +832,7 @@ export class KernelConnection implements Kernel.IKernelConnection { session: this._clientId, content }); - if (parent_header) { - msg.parent_header = parent_header; - } + msg.parent_header = parent_header; this._sendMessage(msg); this._anyMessage.emit({ msg, direction: 'send' }); @@ -997,12 +1000,12 @@ export class KernelConnection implements Kernel.IKernelConnection { // We've seen it before, update existing outputs with same display_id // by handling display_data as update_display_data. const updateMsg: KernelMessage.IMessage = { - header: (JSONExt.deepCopy( - (msg.header as unknown) as JSONObject - ) as unknown) as KernelMessage.IHeader, - parent_header: (JSONExt.deepCopy( - (msg.parent_header as unknown) as JSONObject - ) as unknown) as KernelMessage.IHeader, + header: JSONExt.deepCopy( + msg.header as unknown as JSONObject + ) as unknown as KernelMessage.IHeader, + parent_header: JSONExt.deepCopy( + msg.parent_header as unknown as JSONObject + ) as unknown as KernelMessage.IHeader, metadata: JSONExt.deepCopy(msg.metadata), content: JSONExt.deepCopy(msg.content as JSONObject), channel: msg.channel, @@ -1230,7 +1233,7 @@ export class KernelConnection implements Kernel.IKernelConnection { /** * Create the kernel websocket connection and add socket status handlers. */ - private _createSocket = () => { + private _createSocket = (useProtocols = true) => { this._errorIfDisposed(); // Make sure the socket is clear @@ -1261,7 +1264,13 @@ export class KernelConnection implements Kernel.IKernelConnection { url = url + `&token=${encodeURIComponent(token)}`; } - this._ws = new settings.WebSocket(url); + // Try opening the websocket with our list of subprotocols. + // If the server doesn't handle subprotocols, + // the accepted protocol will be ''. + // But we cannot send '' as a subprotocol, so if connection fails, + // reconnect without subprotocols. + const supportedProtocols = useProtocols ? this._supportedProtocols : []; + this._ws = new settings.WebSocket(url, supportedProtocols); // Ensure incoming binary messages are not Blobs this._ws.binaryType = 'arraybuffer'; @@ -1505,7 +1514,14 @@ export class KernelConnection implements Kernel.IKernelConnection { timeout / 1000 )} seconds.` ); - this._reconnectTimeout = setTimeout(this._createSocket, timeout); + // Try reconnection with subprotocols if the server had supported them. + // Otherwise, try reconnection without subprotocols. + const useProtocols = this._selectedProtocol !== '' ? true : false; + this._reconnectTimeout = setTimeout( + this._createSocket, + timeout, + useProtocols + ); this._reconnectAttempt += 1; } else { this._updateConnectionStatus('disconnected'); @@ -1530,6 +1546,19 @@ export class KernelConnection implements Kernel.IKernelConnection { * Handle a websocket open event. */ private _onWSOpen = (evt: Event) => { + if ( + this._ws!.protocol !== '' && + !this._supportedProtocols.includes(this._ws!.protocol) + ) { + console.log( + 'Server selected unknown kernel wire protocol:', + this._ws!.protocol + ); + this._updateStatus('dead'); + throw new Error(`Unknown kernel wire protocol: ${this._ws!.protocol}`); + } + // Remember the kernel wire protocol selected by the server. + this._selectedProtocol = this._ws!.protocol; this._ws!.onclose = this._onWSClose; this._ws!.onerror = this._onWSClose; this._updateConnectionStatus('connected'); @@ -1542,7 +1571,7 @@ export class KernelConnection implements Kernel.IKernelConnection { // Notify immediately if there is an error with the message. let msg: KernelMessage.IMessage; try { - msg = serialize.deserialize(evt.data); + msg = deserialize(evt.data, this._ws!.protocol); validate.validateMessage(msg); } catch (error) { error.message = `Kernel message validation error: ${error.message}`; @@ -1606,6 +1635,10 @@ export class KernelConnection implements Kernel.IKernelConnection { private _reconnectLimit = 7; private _reconnectAttempt = 0; private _reconnectTimeout: any = null; + private _supportedProtocols: string[] = Object.values( + KernelMessage.supportedKernelWebSocketProtocols + ); + private _selectedProtocol: string = ''; private _futures = new Map< string, @@ -1667,7 +1700,10 @@ namespace Private { */ export async function handleShellMessage< T extends KernelMessage.ShellMessageType - >(kernel: Kernel.IKernelConnection, msg: KernelMessage.IShellMessage) { + >( + kernel: Kernel.IKernelConnection, + msg: KernelMessage.IShellMessage + ): Promise> { const future = kernel.sendShellMessage(msg, true); return future.done; } @@ -1726,7 +1762,7 @@ namespace Private { * that, but doing so would cause your random numbers to follow a non-uniform * distribution, which may not be acceptable for your needs. */ - export function getRandomIntInclusive(min: number, max: number) { + export function getRandomIntInclusive(min: number, max: number): number { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; diff --git a/packages/services/src/kernel/future.ts b/packages/services/src/kernel/future.ts index bfe3649eb146..02fb0e29907b 100644 --- a/packages/services/src/kernel/future.ts +++ b/packages/services/src/kernel/future.ts @@ -21,7 +21,8 @@ export abstract class KernelFutureHandler< REPLY extends KernelMessage.IShellControlMessage > extends DisposableDelegate - implements Kernel.IFuture { + implements Kernel.IFuture +{ /** * Construct a new KernelFutureHandler. */ @@ -155,7 +156,7 @@ export abstract class KernelFutureHandler< */ sendInputReply( content: KernelMessage.IInputReplyMsg['content'], - parent_header?: KernelMessage.IInputReplyMsg['parent_header'] + parent_header: KernelMessage.IInputReplyMsg['parent_header'] ): void { this._kernel.sendInputReply(content, parent_header); } @@ -209,9 +210,9 @@ export abstract class KernelFutureHandler< case 'shell': if ( msg.channel === this.msg.channel && - (msg.parent_header as KernelMessage.IHeader< - KernelMessage.MessageType - >).msg_id === this.msg.header.msg_id + ( + msg.parent_header as KernelMessage.IHeader + ).msg_id === this.msg.header.msg_id ) { await this._handleReply(msg as REPLY); } @@ -311,7 +312,8 @@ export abstract class KernelFutureHandler< } export class KernelControlFutureHandler< - REQUEST extends KernelMessage.IControlMessage = KernelMessage.IControlMessage, + REQUEST extends + KernelMessage.IControlMessage = KernelMessage.IControlMessage, REPLY extends KernelMessage.IControlMessage = KernelMessage.IControlMessage > extends KernelFutureHandler @@ -328,7 +330,7 @@ namespace Private { /** * A no-op function. */ - export const noOp = () => { + export const noOp = (): void => { /* no-op */ }; @@ -463,10 +465,8 @@ namespace Private { this._hooks.length -= numNulls; } - private _hooks: ( - | ((msg: T) => boolean | PromiseLike) - | null - )[] = []; + private _hooks: (((msg: T) => boolean | PromiseLike) | null)[] = + []; private _compactScheduled: boolean; private _processing: Promise; } diff --git a/packages/services/src/kernel/kernel.ts b/packages/services/src/kernel/kernel.ts index 8b0aee26c0c5..2e4655f3f8de 100644 --- a/packages/services/src/kernel/kernel.ts +++ b/packages/services/src/kernel/kernel.ts @@ -1,8 +1,6 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IIterator } from '@lumino/algorithm'; - import { JSONObject, JSONValue } from '@lumino/coreutils'; import { IDisposable, IObservableDisposable } from '@lumino/disposable'; @@ -177,7 +175,7 @@ export interface IKernelConnection extends IObservableDisposable { * @returns A promise that resolves when the kernel has interrupted. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels). * * The promise is fulfilled on a valid response and rejected otherwise. * @@ -194,7 +192,7 @@ export interface IKernelConnection extends IObservableDisposable { * @returns A promise that resolves when the kernel has restarted. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels) and validates the response model. * * Any existing Future or Comm objects are cleared. * @@ -363,15 +361,13 @@ export interface IKernelConnection extends IObservableDisposable { * Send an `input_reply` message. * * @param content - The content of the reply. - * @param parent_header - The parent message header. * * #### Notes * See [Messaging in Jupyter](https://jupyter-client.readthedocs.io/en/latest/messaging.html#messages-on-the-stdin-router-dealer-sockets). - * In v7.0.0, the `parent_header` argument will become mandatory. */ sendInputReply( content: KernelMessage.IInputReplyMsg['content'], - parent_header?: KernelMessage.IInputReplyMsg['parent_header'] + parent_header: KernelMessage.IInputReplyMsg['parent_header'] ): void; /** @@ -522,7 +518,7 @@ export interface IKernelConnection extends IObservableDisposable { * * #### Notes * Uses the [Jupyter Notebook - * API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels). + * API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels). * * On a valid response, closes the websocket, disposes of the kernel * object, and fulfills the promise. @@ -619,7 +615,7 @@ export interface IManager extends IBaseManager { * * @returns A new iterator over the running kernels. */ - running(): IIterator; + running(): IterableIterator; /** * Force a refresh of the running kernels. @@ -782,7 +778,7 @@ export interface IFuture< */ sendInputReply( content: KernelMessage.IInputReplyMsg['content'], - parent_header?: KernelMessage.IInputReplyMsg['parent_header'] + parent_header: KernelMessage.IInputReplyMsg['parent_header'] ): void; } diff --git a/packages/services/src/kernel/manager.ts b/packages/services/src/kernel/manager.ts index d131d9cb417c..870805e91c50 100644 --- a/packages/services/src/kernel/manager.ts +++ b/packages/services/src/kernel/manager.ts @@ -1,10 +1,8 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { every, IIterator, iter } from '@lumino/algorithm'; import { Poll } from '@lumino/polling'; import { ISignal, Signal } from '@lumino/signaling'; - import { ServerConnection } from '..'; import * as Kernel from './kernel'; import { BaseManager } from '../basemanager'; @@ -140,8 +138,8 @@ export class KernelManager extends BaseManager implements Kernel.IManager { * * @returns A new iterator over the running kernels. */ - running(): IIterator { - return iter([...this._models.values()]); + running(): IterableIterator { + return this._models.values(); } /** @@ -258,12 +256,19 @@ export class KernelManager extends BaseManager implements Kernel.IManager { if ( this._models.size === models.length && - every(models, x => { - const existing = this._models.get(x.id); + models.every(model => { + const existing = this._models.get(model.id); if (!existing) { return false; } - return existing.name === x.name; + return ( + existing.connections === model.connections && + existing.execution_state === model.execution_state && + existing.last_activity === model.last_activity && + existing.name === model.name && + existing.reason === model.reason && + existing.traceback === model.traceback + ); }) ) { // Identical models list (presuming models does not contain duplicate @@ -339,6 +344,76 @@ export namespace KernelManager { /** * When the manager stops polling the API. Defaults to `when-hidden`. */ - standby?: Poll.Standby; + standby?: Poll.Standby | (() => boolean | Poll.Standby); + } + + /** + * A no-op kernel manager to be used when starting kernels. + */ + export class NoopManager extends KernelManager { + /** + * Whether the manager is active. + */ + get isActive(): boolean { + return false; + } + + /** + * Used for testing. + */ + get parentReady(): Promise { + return super.ready; + } + + /** + * Start a new kernel - throws an error since it is not supported. + */ + async startNew( + createOptions: IKernelOptions = {}, + connectOptions: Omit< + Kernel.IKernelConnection.IOptions, + 'model' | 'serverSettings' + > = {} + ): Promise { + return Promise.reject( + new Error('Not implemented in no-op Kernel Manager') + ); + } + + /** + * Connect to an existing kernel - throws an error since it is not supported. + */ + connectTo( + options: Omit + ): Kernel.IKernelConnection { + throw new Error('Not implemented in no-op Kernel Manager'); + } + + /** + * Shut down a kernel by id - throws an error since it is not supported. + */ + async shutdown(id: string): Promise { + return Promise.reject( + new Error('Not implemented in no-op Kernel Manager') + ); + } + + /** + * A promise that fulfills when the manager is ready (never). + */ + get ready(): Promise { + return this.parentReady.then(() => this._readyPromise); + } + + /** + * Execute a request to the server to poll running kernels and update state. + */ + protected async requestRunning(): Promise { + return Promise.resolve(); + } + + private _readyPromise = new Promise(() => { + /* no-op */ + }); } } diff --git a/packages/services/src/kernel/messages.ts b/packages/services/src/kernel/messages.ts index 48f9325d4b94..d83384d7c321 100644 --- a/packages/services/src/kernel/messages.ts +++ b/packages/services/src/kernel/messages.ts @@ -299,7 +299,7 @@ export interface IMessage { /** * The parent message */ - parent_header: IHeader | {}; + parent_header: IHeader | Record; } /** @@ -740,7 +740,7 @@ type ReplyContent = T | IReplyErrorContent | IReplyAbortContent; * See [Messaging in Jupyter](https://jupyter-client.readthedocs.io/en/latest/messaging.html#kernel-info). */ export interface IInfoRequestMsg extends IShellMessage<'kernel_info_request'> { - content: {}; + content: Record; } /** @@ -1255,3 +1255,14 @@ export interface IInputReplyMsg extends IStdinMessage<'input_reply'> { export function isInputReplyMsg(msg: IMessage): msg is IInputReplyMsg { return msg.header.msg_type === 'input_reply'; } + +// /////////////////////////////////////////////// +// Message (de)serialization +// /////////////////////////////////////////////// + +/** + * The list of supported kernel wire protocols over websocket. + */ +export enum supportedKernelWebSocketProtocols { + v1KernelWebsocketJupyterOrg = 'v1.kernel.websocket.jupyter.org' +} diff --git a/packages/services/src/kernel/restapi.ts b/packages/services/src/kernel/restapi.ts index c909cbf1bf11..01920fe94aa0 100644 --- a/packages/services/src/kernel/restapi.ts +++ b/packages/services/src/kernel/restapi.ts @@ -9,7 +9,7 @@ import { validateModel, validateModels } from './validate'; * The kernel model provided by the server. * * #### Notes - * See the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels). + * See the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels). */ export interface IModel { /** @@ -62,7 +62,7 @@ export const KERNEL_SERVICE_URL = 'api/kernels'; * @returns A promise that resolves with the list of running kernels. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels) and validates the response model. * * The promise is fulfilled on a valid response and rejected otherwise. */ @@ -88,7 +88,7 @@ export async function listRunning( * @returns A promise that resolves with a kernel connection object. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels) and validates the response model. * * The promise is fulfilled on a valid response and rejected otherwise. */ @@ -120,7 +120,7 @@ export type IKernelOptions = Partial>; * Restart a kernel. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels) and validates the response model. * * The promise is fulfilled on a valid response (and thus after a restart) and rejected otherwise. */ @@ -149,7 +149,7 @@ export async function restartKernel( * Interrupt a kernel. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels) and validates the response model. * * The promise is fulfilled on a valid response and rejected otherwise. */ @@ -182,7 +182,7 @@ export async function interruptKernel( * * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels) and validates the response model. * * The promise is fulfilled on a valid response and rejected otherwise. */ @@ -210,7 +210,7 @@ export async function shutdownKernel( * Get a full kernel model from the server by kernel id string. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernels) and validates the response model. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernels) and validates the response model. * * The promise is fulfilled on a valid response and rejected otherwise. */ diff --git a/packages/services/src/kernel/serialize.ts b/packages/services/src/kernel/serialize.ts index aaf95699860f..bf9ef2ca0acf 100644 --- a/packages/services/src/kernel/serialize.ts +++ b/packages/services/src/kernel/serialize.ts @@ -4,107 +4,280 @@ import * as KernelMessage from './messages'; /** - * Deserialize and return the unpacked message. - * - * #### Notes - * Handles JSON blob strings and binary messages. + * Serialize a kernel message for transport. */ -export function deserialize( - data: ArrayBuffer | string -): KernelMessage.IMessage { - let value: KernelMessage.IMessage; - if (typeof data === 'string') { - value = JSON.parse(data); - } else { - value = deserializeBinary(data); +export function serialize( + msg: KernelMessage.IMessage, + protocol: string = '' +): string | ArrayBuffer { + switch (protocol) { + case KernelMessage.supportedKernelWebSocketProtocols + .v1KernelWebsocketJupyterOrg: + return Private.serializeV1KernelWebsocketJupyterOrg(msg); + default: + return Private.serializeDefault(msg); } - return value; } /** - * Serialize a kernel message for transport. - * - * #### Notes - * If there is binary content, an `ArrayBuffer` is returned, - * otherwise the message is converted to a JSON string. + * Deserialize and return the unpacked message. */ -export function serialize(msg: KernelMessage.IMessage): string | ArrayBuffer { - let value: string | ArrayBuffer; - if (msg.buffers?.length) { - value = serializeBinary(msg); - } else { - value = JSON.stringify(msg); +export function deserialize( + data: ArrayBuffer, + protocol: string = '' +): KernelMessage.IMessage { + switch (protocol) { + case KernelMessage.supportedKernelWebSocketProtocols + .v1KernelWebsocketJupyterOrg: + return Private.deserializeV1KernelWebsocketJupyterOrg(data); + default: + return Private.deserializeDefault(data); } - return value; } -/** - * Deserialize a binary message to a Kernel Message. - */ -function deserializeBinary(buf: ArrayBuffer): KernelMessage.IMessage { - const data = new DataView(buf); - // read the header: 1 + nbufs 32b integers - const nbufs = data.getUint32(0); - const offsets: number[] = []; - if (nbufs < 2) { - throw new Error('Invalid incoming Kernel Message'); +namespace Private { + /** + * Deserialize and return the unpacked message. + * Protocol `v1.kernel.websocket.jupyter.org` + */ + export function deserializeV1KernelWebsocketJupyterOrg( + binMsg: ArrayBuffer + ): KernelMessage.IMessage { + let msg: KernelMessage.IMessage; + const data = new DataView(binMsg); + const offsetNumber: number = Number( + data.getBigUint64(0, true /* littleEndian */) + ); + let offsets: number[] = []; + for (let i = 0; i < offsetNumber; i++) { + // WARNING: we cast our 64-bit unsigned int to a number! + // so offsets cannot index up to 2**64 bytes + offsets.push( + Number(data.getBigUint64(8 * (i + 1), true /* littleEndian */)) + ); + } + const decoder = new TextDecoder('utf8'); + const channel = decoder.decode( + binMsg.slice(offsets[0], offsets[1]) + ) as KernelMessage.Channel; + const header = JSON.parse( + decoder.decode(binMsg.slice(offsets[1], offsets[2])) + ); + const parent_header = JSON.parse( + decoder.decode(binMsg.slice(offsets[2], offsets[3])) + ); + const metadata = JSON.parse( + decoder.decode(binMsg.slice(offsets[3], offsets[4])) + ); + const content = JSON.parse( + decoder.decode(binMsg.slice(offsets[4], offsets[5])) + ); + let buffers = []; + for (let i = 5; i < offsets.length - 1; i++) { + buffers.push(new DataView(binMsg.slice(offsets[i], offsets[i + 1]))); + } + msg = { + channel, + header, + parent_header, + metadata, + content, + buffers + }; + return msg; } - for (let i = 1; i <= nbufs; i++) { - offsets.push(data.getUint32(i * 4)); - } - const jsonBytes = new Uint8Array(buf.slice(offsets[0], offsets[1])); - const msg = JSON.parse(new TextDecoder('utf8').decode(jsonBytes)); - // the remaining chunks are stored as DataViews in msg.buffers - msg.buffers = []; - for (let i = 1; i < nbufs; i++) { - const start = offsets[i]; - const stop = offsets[i + 1] || buf.byteLength; - msg.buffers.push(new DataView(buf.slice(start, stop))); - } - return msg; -} -/** - * Implement the binary serialization protocol. - * - * Serialize Kernel message to ArrayBuffer. - */ -function serializeBinary(msg: KernelMessage.IMessage): ArrayBuffer { - const offsets: number[] = []; - const buffers: ArrayBuffer[] = []; - const encoder = new TextEncoder(); - let origBuffers: (ArrayBuffer | ArrayBufferView)[] = []; - if (msg.buffers !== undefined) { - origBuffers = msg.buffers; - delete msg['buffers']; + /** + * Serialize a kernel message for transport. + * Protocol `v1.kernel.websocket.jupyter.org` + */ + export function serializeV1KernelWebsocketJupyterOrg( + msg: KernelMessage.IMessage + ): ArrayBuffer { + const header = JSON.stringify(msg.header); + const parentHeader = + msg.parent_header == null ? '{}' : JSON.stringify(msg.parent_header); + const metadata = JSON.stringify(msg.metadata); + const content = JSON.stringify(msg.content); + const buffers: (ArrayBuffer | ArrayBufferView)[] = + msg.buffers !== undefined ? msg.buffers : []; + const offsetNumber: number = 1 + 4 + buffers.length + 1; + let offsets: number[] = []; + offsets.push(8 * (1 + offsetNumber)); + offsets.push(msg.channel.length + offsets[offsets.length - 1]); + const encoder = new TextEncoder(); + const channelEncoded = encoder.encode(msg.channel); + const headerEncoded = encoder.encode(header); + const parentHeaderEncoded = encoder.encode(parentHeader); + const metadataEncoded = encoder.encode(metadata); + const contentEncoded = encoder.encode(content); + const binMsgNoBuff = new Uint8Array( + channelEncoded.length + + headerEncoded.length + + parentHeaderEncoded.length + + metadataEncoded.length + + contentEncoded.length + ); + binMsgNoBuff.set(channelEncoded); + binMsgNoBuff.set(headerEncoded, channelEncoded.length); + binMsgNoBuff.set( + parentHeaderEncoded, + channelEncoded.length + headerEncoded.length + ); + binMsgNoBuff.set( + metadataEncoded, + channelEncoded.length + headerEncoded.length + parentHeaderEncoded.length + ); + binMsgNoBuff.set( + contentEncoded, + channelEncoded.length + + headerEncoded.length + + parentHeaderEncoded.length + + metadataEncoded.length + ); + for (let length of [ + headerEncoded.length, + parentHeaderEncoded.length, + metadataEncoded.length, + contentEncoded.length + ]) { + offsets.push(length + offsets[offsets.length - 1]); + } + let buffersByteLength = 0; + for (let buffer of buffers) { + let length = buffer.byteLength; + offsets.push(length + offsets[offsets.length - 1]); + buffersByteLength += length; + } + const binMsg = new Uint8Array( + 8 * (1 + offsetNumber) + binMsgNoBuff.byteLength + buffersByteLength + ); + const word = new ArrayBuffer(8); + const data = new DataView(word); + data.setBigUint64(0, BigInt(offsetNumber), true /* littleEndian */); + binMsg.set(new Uint8Array(word), 0); + for (let i = 0; i < offsets.length; i++) { + data.setBigUint64(0, BigInt(offsets[i]), true /* littleEndian */); + binMsg.set(new Uint8Array(word), 8 * (i + 1)); + } + binMsg.set(binMsgNoBuff, offsets[0]); + for (let i = 0; i < buffers.length; i++) { + const buffer = buffers[i]; + binMsg.set( + new Uint8Array(ArrayBuffer.isView(buffer) ? buffer.buffer : buffer), + offsets[5 + i] + ); + } + return binMsg.buffer; } - const jsonUtf8 = encoder.encode(JSON.stringify(msg)); - buffers.push(jsonUtf8.buffer); - for (let i = 0; i < origBuffers.length; i++) { - // msg.buffers elements could be either views or ArrayBuffers - // buffers elements are ArrayBuffers - const b: any = origBuffers[i]; - buffers.push(ArrayBuffer.isView(b) ? b.buffer : b); + + /** + * Deserialize and return the unpacked message. + * Default protocol + * + * #### Notes + * Handles JSON blob strings and binary messages. + */ + export function deserializeDefault( + data: ArrayBuffer | string + ): KernelMessage.IMessage { + let value: KernelMessage.IMessage; + if (typeof data === 'string') { + value = JSON.parse(data); + } else { + value = deserializeBinary(data); + } + return value; } - const nbufs = buffers.length; - offsets.push(4 * (nbufs + 1)); - for (let i = 0; i + 1 < buffers.length; i++) { - offsets.push(offsets[offsets.length - 1] + buffers[i].byteLength); + + /** + * Serialize a kernel message for transport. + * Default protocol + * + * #### Notes + * If there is binary content, an `ArrayBuffer` is returned, + * otherwise the message is converted to a JSON string. + */ + export function serializeDefault( + msg: KernelMessage.IMessage + ): string | ArrayBuffer { + let value: string | ArrayBuffer; + if (msg.buffers?.length) { + value = serializeBinary(msg); + } else { + value = JSON.stringify(msg); + } + return value; } - const msgBuf = new Uint8Array( - offsets[offsets.length - 1] + buffers[buffers.length - 1].byteLength - ); - // use DataView.setUint32 for network byte-order - const view = new DataView(msgBuf.buffer); - // write nbufs to first 4 bytes - view.setUint32(0, nbufs); - // write offsets to next 4 * nbufs bytes - for (let i = 0; i < offsets.length; i++) { - view.setUint32(4 * (i + 1), offsets[i]); + + /** + * Deserialize a binary message to a Kernel Message. + */ + function deserializeBinary(buf: ArrayBuffer): KernelMessage.IMessage { + const data = new DataView(buf); + // read the header: 1 + nbufs 32b integers + const nbufs = data.getUint32(0); + const offsets: number[] = []; + if (nbufs < 2) { + throw new Error('Invalid incoming Kernel Message'); + } + for (let i = 1; i <= nbufs; i++) { + offsets.push(data.getUint32(i * 4)); + } + const jsonBytes = new Uint8Array(buf.slice(offsets[0], offsets[1])); + const msg = JSON.parse(new TextDecoder('utf8').decode(jsonBytes)); + // the remaining chunks are stored as DataViews in msg.buffers + msg.buffers = []; + for (let i = 1; i < nbufs; i++) { + const start = offsets[i]; + const stop = offsets[i + 1] || buf.byteLength; + msg.buffers.push(new DataView(buf.slice(start, stop))); + } + return msg; } - // write all the buffers at their respective offsets - for (let i = 0; i < buffers.length; i++) { - msgBuf.set(new Uint8Array(buffers[i]), offsets[i]); + + /** + * Implement the binary serialization protocol. + * + * Serialize Kernel message to ArrayBuffer. + */ + function serializeBinary(msg: KernelMessage.IMessage): ArrayBuffer { + const offsets: number[] = []; + const buffers: ArrayBuffer[] = []; + const encoder = new TextEncoder(); + let origBuffers: (ArrayBuffer | ArrayBufferView)[] = []; + if (msg.buffers !== undefined) { + origBuffers = msg.buffers; + delete msg['buffers']; + } + const jsonUtf8 = encoder.encode(JSON.stringify(msg)); + buffers.push(jsonUtf8.buffer); + for (let i = 0; i < origBuffers.length; i++) { + // msg.buffers elements could be either views or ArrayBuffers + // buffers elements are ArrayBuffers + const b: any = origBuffers[i]; + buffers.push(ArrayBuffer.isView(b) ? b.buffer : b); + } + const nbufs = buffers.length; + offsets.push(4 * (nbufs + 1)); + for (let i = 0; i + 1 < buffers.length; i++) { + offsets.push(offsets[offsets.length - 1] + buffers[i].byteLength); + } + const msgBuf = new Uint8Array( + offsets[offsets.length - 1] + buffers[buffers.length - 1].byteLength + ); + // use DataView.setUint32 for network byte-order + const view = new DataView(msgBuf.buffer); + // write nbufs to first 4 bytes + view.setUint32(0, nbufs); + // write offsets to next 4 * nbufs bytes + for (let i = 0; i < offsets.length; i++) { + view.setUint32(4 * (i + 1), offsets[i]); + } + // write all the buffers at their respective offsets + for (let i = 0; i < buffers.length; i++) { + msgBuf.set(new Uint8Array(buffers[i]), offsets[i]); + } + return msgBuf.buffer; } - return msgBuf.buffer; } diff --git a/packages/services/src/kernelspec/manager.ts b/packages/services/src/kernelspec/manager.ts index 717a771f2bf6..93d2325e4186 100644 --- a/packages/services/src/kernelspec/manager.ts +++ b/packages/services/src/kernelspec/manager.ts @@ -14,7 +14,8 @@ import { BaseManager } from '../basemanager'; */ export class KernelSpecManager extends BaseManager - implements KernelSpec.IManager { + implements KernelSpec.IManager +{ /** * Construct a new kernel spec manager. * @@ -147,6 +148,6 @@ export namespace KernelSpecManager { /** * When the manager stops polling the API. Defaults to `when-hidden`. */ - standby?: Poll.Standby; + standby?: Poll.Standby | (() => boolean | Poll.Standby); } } diff --git a/packages/services/src/kernelspec/restapi.ts b/packages/services/src/kernelspec/restapi.ts index 4d744fcac326..169190f6e5ed 100644 --- a/packages/services/src/kernelspec/restapi.ts +++ b/packages/services/src/kernelspec/restapi.ts @@ -21,7 +21,7 @@ const KERNELSPEC_SERVICE_URL = 'api/kernelspecs'; * @returns A promise that resolves with the kernel specs. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernelspecs). */ export async function getSpecs( settings: ServerConnection.ISettings = ServerConnection.makeSettings() @@ -83,7 +83,7 @@ export interface ISpecModel extends PartialJSONObject { * The available kernelSpec models. * * #### Notes - * See the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). + * See the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/kernelspecs). */ export interface ISpecModels extends PartialJSONObject { /** diff --git a/packages/services/src/kernelspec/validate.ts b/packages/services/src/kernelspec/validate.ts index f658b2cdee73..f7b4115b3a14 100644 --- a/packages/services/src/kernelspec/validate.ts +++ b/packages/services/src/kernelspec/validate.ts @@ -7,6 +7,7 @@ import { validateProperty } from '../validate'; /** * Validate a server kernelspec model to a client side model. */ +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function validateSpecModel(data: any): ISpecModel { const spec = data.spec; if (!spec) { @@ -43,6 +44,7 @@ export function validateSpecModel(data: any): ISpecModel { /** * Validate a `Kernel.ISpecModels` object. */ +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function validateSpecModels(data: any): ISpecModels { if (!data.hasOwnProperty('kernelspecs')) { throw new Error('No kernelspecs found'); diff --git a/packages/services/src/manager.ts b/packages/services/src/manager.ts index 9eaece45b93f..183dad9088f0 100644 --- a/packages/services/src/manager.ts +++ b/packages/services/src/manager.ts @@ -9,24 +9,24 @@ import { ISignal, Signal } from '@lumino/signaling'; import { Builder, BuildManager } from './builder'; -import { NbConvert, NbConvertManager } from './nbconvert'; - import { Contents, ContentsManager } from './contents'; import { Event, EventManager } from './event'; -import { KernelManager } from './kernel'; +import { Kernel, KernelManager } from './kernel'; import { KernelSpec, KernelSpecManager } from './kernelspec'; +import { NbConvert, NbConvertManager } from './nbconvert'; + +import { ServerConnection } from './serverconnection'; + import { Session, SessionManager } from './session'; import { Setting, SettingManager } from './setting'; import { Terminal, TerminalManager } from './terminal'; -import { ServerConnection } from './serverconnection'; - import { User, UserManager } from './user'; import { Workspace, WorkspaceManager } from './workspace'; @@ -38,28 +38,30 @@ export class ServiceManager implements ServiceManager.IManager { /** * Construct a new services provider. */ - constructor(options: ServiceManager.IOptions = {}) { + constructor(options: Partial = {}) { const defaultDrive = options.defaultDrive; const serverSettings = options.serverSettings ?? ServerConnection.makeSettings(); const standby = options.standby ?? 'when-hidden'; const normalized = { defaultDrive, serverSettings, standby }; - const kernelManager = new KernelManager(normalized); this.serverSettings = serverSettings; - this.contents = new ContentsManager(normalized); - this.events = new EventManager(normalized); - this.sessions = new SessionManager({ - ...normalized, - kernelManager: kernelManager - }); - this.settings = new SettingManager(normalized); - this.terminals = new TerminalManager(normalized); - this.builder = new BuildManager(normalized); - this.workspaces = new WorkspaceManager(normalized); - this.nbconvert = new NbConvertManager(normalized); - this.kernelspecs = new KernelSpecManager(normalized); - this.user = new UserManager(normalized); + this.contents = options.contents || new ContentsManager(normalized); + this.events = options.events || new EventManager(normalized); + this.kernels = options.kernels || new KernelManager(normalized); + this.sessions = + options.sessions || + new SessionManager({ + ...normalized, + kernelManager: this.kernels + }); + this.settings = options.settings || new SettingManager(normalized); + this.terminals = options.terminals || new TerminalManager(normalized); + this.builder = options.builder || new BuildManager(normalized); + this.workspaces = options.workspaces || new WorkspaceManager(normalized); + this.nbconvert = options.nbconvert || new NbConvertManager(normalized); + this.kernelspecs = options.kernelspecs || new KernelSpecManager(normalized); + this.user = options.user || new UserManager(normalized); // Proxy all connection failures from the individual service managers. this.kernelspecs.connectionFailure.connect(this._onConnectionFailure, this); @@ -115,27 +117,32 @@ export class ServiceManager implements ServiceManager.IManager { /** * Get the session manager instance. */ - readonly sessions: SessionManager; + readonly sessions: Session.IManager; /** - * Get the session manager instance. + * Get the kernel manager instance. */ - readonly kernelspecs: KernelSpecManager; + readonly kernels: Kernel.IManager; + + /** + * Get the kernelspec manager instance. + */ + readonly kernelspecs: KernelSpec.IManager; /** * Get the setting manager instance. */ - readonly settings: SettingManager; + readonly settings: Setting.IManager; /** * The builder for the manager. */ - readonly builder: BuildManager; + readonly builder: Builder.IManager; /** * Get the contents manager instance. */ - readonly contents: ContentsManager; + readonly contents: Contents.IManager; /** * The event manager instance. @@ -145,7 +152,7 @@ export class ServiceManager implements ServiceManager.IManager { /** * Get the terminal manager instance. */ - readonly terminals: TerminalManager; + readonly terminals: Terminal.IManager; /** * Get the user manager instance. @@ -155,12 +162,12 @@ export class ServiceManager implements ServiceManager.IManager { /** * Get the workspace manager instance. */ - readonly workspaces: WorkspaceManager; + readonly workspaces: Workspace.IManager; /** * Get the nbconvert manager instance. */ - readonly nbconvert: NbConvertManager; + readonly nbconvert: NbConvert.IManager; /** * Test whether the manager is ready. @@ -193,9 +200,46 @@ export namespace ServiceManager { /** * A service manager interface. */ - export interface IManager extends IDisposable { + export interface IManager extends IDisposable, IManagers { + /** + * Test whether the manager is ready. + */ + readonly isReady: boolean; + + /** + * A promise that fulfills when the manager is initially ready. + */ + readonly ready: Promise; + + /** + * A signal emitted when there is a connection failure with the server. + */ + readonly connectionFailure: ISignal; + } + + /** + * The options used to create a service manager. + */ + export interface IOptions extends IManagers { + /** + * The default drive for the contents manager. + */ + readonly defaultDrive: Contents.IDrive; + + /** + * When the manager stops polling the API. Defaults to `when-hidden`. + */ + standby: Poll.Standby | (() => boolean | Poll.Standby); + } + + /** + * The managers provided by the service manager. + */ + interface IManagers { /** * The builder for the manager. + * + * @deprecated will be removed in JupyterLab v5 */ readonly builder: Builder.IManager; @@ -206,16 +250,8 @@ export namespace ServiceManager { /** * The events service manager. - * - * #### Notes - * The events manager is optional until JupyterLab 4. */ - readonly events?: Event.IManager; - - /** - * Test whether the manager is ready. - */ - readonly isReady: boolean; + readonly events: Event.IManager; /** * A promise that fulfills when the manager is initially ready. @@ -233,7 +269,12 @@ export namespace ServiceManager { readonly sessions: Session.IManager; /** - * The session manager for the manager. + * The kernel manager of the manager. + */ + readonly kernels: Kernel.IManager; + + /** + * The kernelspec manager for the manager. */ readonly kernelspecs: KernelSpec.IManager; @@ -250,7 +291,7 @@ export namespace ServiceManager { /** * The user manager for the manager. */ - readonly user?: User.IManager; + readonly user: User.IManager; /** * The workspace manager for the manager. @@ -261,30 +302,5 @@ export namespace ServiceManager { * The nbconvert manager for the manager. */ readonly nbconvert: NbConvert.IManager; - - /** - * A signal emitted when there is a connection failure with the server. - */ - readonly connectionFailure: ISignal; - } - - /** - * The options used to create a service manager. - */ - export interface IOptions { - /** - * The server settings of the manager. - */ - readonly serverSettings?: ServerConnection.ISettings; - - /** - * The default drive for the contents manager. - */ - readonly defaultDrive?: Contents.IDrive; - - /** - * When the manager stops polling the API. Defaults to `when-hidden`. - */ - standby?: Poll.Standby; } } diff --git a/packages/services/src/nbconvert/index.ts b/packages/services/src/nbconvert/index.ts index 3e0e2c403f35..1bb6f86522ad 100644 --- a/packages/services/src/nbconvert/index.ts +++ b/packages/services/src/nbconvert/index.ts @@ -5,6 +5,8 @@ import { URLExt } from '@jupyterlab/coreutils'; import { ServerConnection } from '../serverconnection'; +import { PromiseDelegate } from '@lumino/coreutils'; + /** * The url for the lab nbconvert service. */ @@ -28,9 +30,11 @@ export class NbConvertManager { readonly serverSettings: ServerConnection.ISettings; /** - * Get whether the application should be built. + * Fetch and cache the export formats from the expensive nbconvert handler. */ - async getExportFormats(): Promise { + protected async fetchExportFormats(): Promise { + this._requestingFormats = new PromiseDelegate(); + this._exportFormats = null; const base = this.serverSettings.baseUrl; const url = URLExt.join(base, NBCONVERT_SETTINGS_URL); const { serverSettings } = this; @@ -50,8 +54,30 @@ export class NbConvertManager { const mimeType: string = data[key].output_mimetype; exportList[key] = { output_mimetype: mimeType }; }); + this._exportFormats = exportList; + this._requestingFormats.resolve(exportList); return exportList; } + + /** + * Get the list of export formats, preferring pre-cached ones. + */ + async getExportFormats( + force: boolean = true + ): Promise { + if (this._requestingFormats) { + return this._requestingFormats.promise; + } + + if (force || !this._exportFormats) { + return await this.fetchExportFormats(); + } + + return this._exportFormats; + } + + protected _requestingFormats: PromiseDelegate | null; + protected _exportFormats: NbConvertManager.IExportFormats | null = null; } /** diff --git a/packages/services/src/serverconnection.ts b/packages/services/src/serverconnection.ts index 8baeffac7903..f7cdfced3a98 100644 --- a/packages/services/src/serverconnection.ts +++ b/packages/services/src/serverconnection.ts @@ -3,30 +3,13 @@ import { PageConfig, URLExt } from '@jupyterlab/coreutils'; -/** - * Handle the default `fetch` and `WebSocket` providers. - */ -declare let global: any; - -let FETCH: (input: RequestInfo, init?: RequestInit) => Promise; -let HEADERS: typeof Headers; -let REQUEST: typeof Request; let WEBSOCKET: typeof WebSocket; if (typeof window === 'undefined') { // Mangle the require statements so it does not get picked up in the // browser assets. - /* tslint:disable */ - const fetchMod = require('node-fetch'); - FETCH = global.fetch ?? fetchMod; - REQUEST = global.Request ?? fetchMod.Request; - HEADERS = global.Headers ?? fetchMod.Headers; WEBSOCKET = require('ws'); - /* tslint:enable */ } else { - FETCH = fetch; - REQUEST = Request; - HEADERS = Headers; WEBSOCKET = WebSocket; } @@ -113,7 +96,7 @@ export namespace ServerConnection { * * @returns The full settings object. */ - export function makeSettings(options?: Partial) { + export function makeSettings(options?: Partial): ISettings { return Private.makeSettings(options); } @@ -244,9 +227,9 @@ namespace Private { return { init: { cache: 'no-store', credentials: 'same-origin' }, - fetch: FETCH, - Headers: HEADERS, - Request: REQUEST, + fetch, + Headers, + Request, WebSocket: WEBSOCKET, token: PageConfig.getToken(), appUrl: PageConfig.getOption('appUrl'), diff --git a/packages/services/src/session/default.ts b/packages/services/src/session/default.ts index a40278eecf5e..448ed71b42b1 100644 --- a/packages/services/src/session/default.ts +++ b/packages/services/src/session/default.ts @@ -267,7 +267,7 @@ export class SessionConnection implements Session.ISessionConnection { /** * Change the kernel. * - * @params options - The name or id of the new kernel. + * @param options - The name or id of the new kernel. * * #### Notes * This shuts down the existing kernel and creates a new kernel, @@ -290,7 +290,7 @@ export class SessionConnection implements Session.ISessionConnection { * @returns - The promise fulfilled on a valid response from the server. * * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/sessions), and validates the response. + * Uses the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/sessions), and validates the response. * Disposes of the session and emits a [sessionDied] signal on success. */ async shutdown(): Promise { @@ -334,7 +334,7 @@ export class SessionConnection implements Session.ISessionConnection { protected onKernelStatus( sender: Kernel.IKernelConnection, state: Kernel.Status - ) { + ): void { this._statusChanged.emit(state); } @@ -344,7 +344,7 @@ export class SessionConnection implements Session.ISessionConnection { protected onKernelConnectionStatus( sender: Kernel.IKernelConnection, state: Kernel.ConnectionStatus - ) { + ): void { this._connectionStatusChanged.emit(state); } @@ -361,7 +361,7 @@ export class SessionConnection implements Session.ISessionConnection { protected onIOPubMessage( sender: Kernel.IKernelConnection, msg: KernelMessage.IIOPubMessage - ) { + ): void { this._iopubMessage.emit(msg); } @@ -371,7 +371,7 @@ export class SessionConnection implements Session.ISessionConnection { protected onUnhandledMessage( sender: Kernel.IKernelConnection, msg: KernelMessage.IMessage - ) { + ): void { this._unhandledMessage.emit(msg); } @@ -381,7 +381,7 @@ export class SessionConnection implements Session.ISessionConnection { protected onAnyMessage( sender: Kernel.IKernelConnection, args: Kernel.IAnyMessageArgs - ) { + ): void { this._anyMessage.emit(args); } diff --git a/packages/services/src/session/manager.ts b/packages/services/src/session/manager.ts index 5ccfd0e06f41..d6dc5a009622 100644 --- a/packages/services/src/session/manager.ts +++ b/packages/services/src/session/manager.ts @@ -1,12 +1,9 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { every, IIterator, iter } from '@lumino/algorithm'; import { Poll } from '@lumino/polling'; import { ISignal, Signal } from '@lumino/signaling'; - import { ServerConnection } from '../serverconnection'; - import * as Session from './session'; import { BaseManager } from '../basemanager'; import { SessionConnection } from './default'; @@ -44,7 +41,9 @@ export class SessionManager extends BaseManager implements Session.IManager { this._ready = (async () => { await this._pollModels.start(); await this._pollModels.tick; - await this._kernelManager.ready; + if (this._kernelManager.isActive) { + await this._kernelManager.ready; + } this._isReady = true; })(); } @@ -126,8 +125,8 @@ export class SessionManager extends BaseManager implements Session.IManager { * * @returns A new iterator over the running sessions. */ - running(): IIterator { - return iter([...this._models.values()]); + running(): IterableIterator { + return this._models.values(); } /** @@ -268,17 +267,17 @@ export class SessionManager extends BaseManager implements Session.IManager { if ( this._models.size === models.length && - every(models, x => { - const existing = this._models.get(x.id); + models.every(model => { + const existing = this._models.get(model.id); if (!existing) { return false; } return ( - existing.kernel?.id === x.kernel?.id && - existing.kernel?.name === x.kernel?.name && - existing.name === x.name && - existing.path === x.path && - existing.type === x.type + existing.kernel?.id === model.kernel?.id && + existing.kernel?.name === model.kernel?.name && + existing.name === model.name && + existing.path === model.path && + existing.type === model.type ); }) ) { @@ -357,11 +356,84 @@ export namespace SessionManager { /** * When the manager stops polling the API. Defaults to `when-hidden`. */ - standby?: Poll.Standby; + standby?: Poll.Standby | (() => boolean | Poll.Standby); /** * Kernel Manager */ kernelManager: Kernel.IManager; } + + /** + * A no-op session manager to be used when starting sessions is not supported. + */ + export class NoopManager extends SessionManager { + /** + * Whether the manager is active. + */ + get isActive(): boolean { + return false; + } + + /** + * Used for testing. + */ + get parentReady(): Promise { + return super.ready; + } + + /** + * Start a new session - throw an error since it is not supported. + */ + async startNew( + createOptions: Session.ISessionOptions, + connectOptions: Omit< + Session.ISessionConnection.IOptions, + 'model' | 'connectToKernel' | 'serverSettings' + > = {} + ): Promise { + return Promise.reject( + new Error('Not implemented in no-op Session Manager') + ); + } + + /* + * Connect to a running session - throw an error since it is not supported. + */ + connectTo( + options: Omit< + Session.ISessionConnection.IOptions, + 'connectToKernel' | 'serverSettings' + > + ): Session.ISessionConnection { + throw Error('Not implemented in no-op Session Manager'); + } + + /** + * A promise that fulfills when the manager is ready (never). + */ + get ready(): Promise { + return this.parentReady.then(() => this._readyPromise); + } + + /** + * Shut down a session by id - throw an error since it is not supported. + */ + async shutdown(id: string): Promise { + return Promise.reject( + new Error('Not implemented in no-op Session Manager') + ); + } + + /** + * Execute a request to the server to poll running sessions and update state. + */ + protected async requestRunning(): Promise { + return Promise.resolve(); + } + + private _readyPromise = new Promise(() => { + /* no-op */ + }); + } } diff --git a/packages/services/src/session/session.ts b/packages/services/src/session/session.ts index 10d873b019d2..517894efbb2c 100644 --- a/packages/services/src/session/session.ts +++ b/packages/services/src/session/session.ts @@ -1,8 +1,6 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IIterator } from '@lumino/algorithm'; - import { IDisposable, IObservableDisposable } from '@lumino/disposable'; import { ISignal } from '@lumino/signaling'; @@ -271,7 +269,7 @@ export interface IManager extends IDisposable { * * @returns A new iterator over the running sessions. */ - running(): IIterator; + running(): IterableIterator; /** * Start a new session. @@ -369,7 +367,7 @@ export interface IManager extends IDisposable { * The session model returned by the server. * * #### Notes - * See the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/sessions). + * See the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/sessions). */ export interface IModel { /** @@ -390,7 +388,7 @@ export interface IModel { * parameter is not technically required, but is often assumed to be nonempty, * so we require it too. * - * See the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/sessions). + * See the [Jupyter Notebook API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter-server/jupyter_server/main/jupyter_server/services/api/api.yaml#!/sessions). */ export type ISessionOptions = Pick & { kernel?: Partial>; diff --git a/packages/services/src/session/validate.ts b/packages/services/src/session/validate.ts index c71483e090d4..0a8eb9888587 100644 --- a/packages/services/src/session/validate.ts +++ b/packages/services/src/session/validate.ts @@ -10,6 +10,7 @@ import { validateProperty } from '../validate'; /** * Validate an `Session.IModel` object. */ +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function validateModel(data: any): asserts data is Session.IModel { validateProperty(data, 'id', 'string'); validateProperty(data, 'type', 'string'); @@ -22,6 +23,7 @@ export function validateModel(data: any): asserts data is Session.IModel { /** * Update model from legacy session data. */ +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function updateLegacySessionModel(data: any): void { if (data.path === undefined && data.notebook !== undefined) { data.path = data.notebook.path; diff --git a/packages/services/src/setting/index.ts b/packages/services/src/setting/index.ts index 146646f76e7c..7fd299fcaa86 100644 --- a/packages/services/src/setting/index.ts +++ b/packages/services/src/setting/index.ts @@ -68,12 +68,14 @@ export class SettingManager extends DataConnector< * * @returns A promise that resolves if successful. */ - async list(): Promise<{ ids: string[]; values: ISettingRegistry.IPlugin[] }> { + async list( + query?: 'ids' + ): Promise<{ ids: string[]; values: ISettingRegistry.IPlugin[] }> { const { serverSettings } = this; const { baseUrl, appUrl } = serverSettings; const { makeRequest, ResponseError } = ServerConnection; const base = baseUrl + appUrl; - const url = Private.url(base, ''); + const url = Private.url(base, '', query === 'ids'); const response = await makeRequest(url, {}, serverSettings); if (response.status !== 200) { @@ -81,12 +83,19 @@ export class SettingManager extends DataConnector< } const json = await response.json(); - const values: ISettingRegistry.IPlugin[] = - json?.['settings']?.map((plugin: ISettingRegistry.IPlugin) => { - plugin.data = { composite: {}, user: {} }; - return plugin; - }) ?? []; - const ids = values.map(plugin => plugin.id); + const ids = + json?.['settings']?.map( + (plugin: ISettingRegistry.IPlugin) => plugin.id + ) ?? []; + + let values: ISettingRegistry.IPlugin[] = []; + if (!query) { + values = + json?.['settings']?.map((plugin: ISettingRegistry.IPlugin) => { + plugin.data = { composite: {}, user: {} }; + return plugin; + }) ?? []; + } return { ids, values }; } @@ -148,7 +157,10 @@ namespace Private { /** * Get the url for a plugin's settings. */ - export function url(base: string, id: string): string { - return URLExt.join(base, SERVICE_SETTINGS_URL, id); + export function url(base: string, id: string, idsOnly?: boolean): string { + const idsOnlyParam = idsOnly + ? URLExt.objectToQueryString({ ids_only: true }) + : ''; + return `${URLExt.join(base, SERVICE_SETTINGS_URL, id)}${idsOnlyParam}`; } } diff --git a/packages/services/src/shim/ws.ts b/packages/services/src/shim/ws.ts index 5b82f34d0df3..24e02ee4faaa 100644 --- a/packages/services/src/shim/ws.ts +++ b/packages/services/src/shim/ws.ts @@ -1 +1,6 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + export default WebSocket; diff --git a/packages/services/src/terminal/default.ts b/packages/services/src/terminal/default.ts index 7d8da80bee2c..8e019e6c6230 100644 --- a/packages/services/src/terminal/default.ts +++ b/packages/services/src/terminal/default.ts @@ -171,7 +171,7 @@ export class TerminalConnection implements Terminal.ITerminalConnection { /** * Attempt a connection if we have not exhausted connection attempts. */ - _reconnect() { + _reconnect(): void { this._errorIfDisposed(); // Clear any existing reconnection attempt @@ -402,7 +402,7 @@ namespace Private { * that, but doing so would cause your random numbers to follow a non-uniform * distribution, which may not be acceptable for your needs. */ - export function getRandomIntInclusive(min: number, max: number) { + export function getRandomIntInclusive(min: number, max: number): number { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; diff --git a/packages/services/src/terminal/manager.ts b/packages/services/src/terminal/manager.ts index 0fdb7cb5ca80..088953234347 100644 --- a/packages/services/src/terminal/manager.ts +++ b/packages/services/src/terminal/manager.ts @@ -1,8 +1,6 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IIterator, iter } from '@lumino/algorithm'; - import { Poll } from '@lumino/polling'; import { ISignal, Signal } from '@lumino/signaling'; @@ -143,8 +141,8 @@ export class TerminalManager extends BaseManager implements Terminal.IManager { * * @returns A new iterator over the running terminals. */ - running(): IIterator { - return iter(this._models); + running(): IterableIterator { + return this._models[Symbol.iterator](); } /** @@ -297,6 +295,73 @@ export namespace TerminalManager { /** * When the manager stops polling the API. Defaults to `when-hidden`. */ - standby?: Poll.Standby; + standby?: Poll.Standby | (() => boolean | Poll.Standby); + } + + /** + * A no-op terminal manager to be used when starting terminals is not supported. + */ + export class NoopManager extends TerminalManager { + /** + * Whether the manager is active. + */ + get isActive(): boolean { + return false; + } + + /** + * Used for testing. + */ + get parentReady(): Promise { + return super.ready; + } + + /** + * A promise that fulfills when the manager is ready (never). + */ + get ready(): Promise { + return this.parentReady.then(() => this._readyPromise); + } + + /** + * Create a new terminal session - throw an error since it is not supported. + * + */ + async startNew( + options?: Terminal.ITerminal.IOptions + ): Promise { + return Promise.reject( + new Error('Not implemented in no-op Terminal Manager') + ); + } + + /* + * Connect to a running terminal - throw an error since it is not supported. + */ + connectTo( + options: Omit + ): Terminal.ITerminalConnection { + throw Error('Not implemented in no-op Terminal Manager'); + } + + /** + * Shut down a session by id - throw an error since it is not supported. + */ + async shutdown(id: string): Promise { + return Promise.reject( + new Error('Not implemented in no-op Terminal Manager') + ); + } + + /** + * Execute a request to the server to poll running sessions and update state. + */ + protected async requestRunning(): Promise { + return Promise.resolve(); + } + + private _readyPromise = new Promise(() => { + /* no-op */ + }); } } diff --git a/packages/services/src/terminal/restapi.ts b/packages/services/src/terminal/restapi.ts index f5979aae5e37..4b36c9bfaf45 100644 --- a/packages/services/src/terminal/restapi.ts +++ b/packages/services/src/terminal/restapi.ts @@ -120,7 +120,7 @@ namespace Private { /** * Throw an error if terminals are not available. */ - export function errorIfNotAvailable() { + export function errorIfNotAvailable(): void { if (!isAvailable()) { throw new Error('Terminals Unavailable'); } diff --git a/packages/services/src/terminal/terminal.ts b/packages/services/src/terminal/terminal.ts index 003d7e6c1211..5c2d5f2a4028 100644 --- a/packages/services/src/terminal/terminal.ts +++ b/packages/services/src/terminal/terminal.ts @@ -1,8 +1,6 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IIterator } from '@lumino/algorithm'; - import { JSONPrimitive } from '@lumino/coreutils'; import { IObservableDisposable } from '@lumino/disposable'; @@ -153,7 +151,7 @@ export interface IManager extends IBaseManager { * * @returns A new iterator over the running terminals. */ - running(): IIterator; + running(): IterableIterator; /** * Create a new terminal session. diff --git a/packages/services/src/testutils.ts b/packages/services/src/testutils.ts new file mode 100644 index 000000000000..ccd582062589 --- /dev/null +++ b/packages/services/src/testutils.ts @@ -0,0 +1,811 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +// We explicitly reference the jest typings since the jest.d.ts file shipped +// with jest 26 masks the @types/jest typings + +/// + +import { PathExt } from '@jupyterlab/coreutils'; +import { PartialJSONObject, ReadonlyJSONObject, UUID } from '@lumino/coreutils'; +import { AttachedProperty } from '@lumino/properties'; +import { ISignal, Signal } from '@lumino/signaling'; +import { BaseManager } from './basemanager'; +import { Contents, ContentsManager } from './contents'; +import { Kernel, KernelMessage } from './kernel'; +import { KernelSpec } from './kernelspec'; +import { ServiceManager } from './manager'; +import { ServerConnection } from './serverconnection'; +import { Session } from './session'; +import { User, UserManager } from './user'; + +// The default kernel name +export const DEFAULT_NAME = 'python3'; + +export const KERNELSPECS: { [key: string]: KernelSpec.ISpecModel } = { + [DEFAULT_NAME]: { + argv: [ + '/Users/someuser/miniconda3/envs/jupyterlab/bin/python', + '-m', + 'ipykernel_launcher', + '-f', + '{connection_file}' + ], + display_name: 'Python 3', + language: 'python', + metadata: {}, + name: DEFAULT_NAME, + resources: {} + }, + irkernel: { + argv: [ + '/Users/someuser/miniconda3/envs/jupyterlab/bin/python', + '-m', + 'ipykernel_launcher', + '-f', + '{connection_file}' + ], + display_name: 'R', + language: 'r', + metadata: {}, + name: 'irkernel', + resources: {} + } +}; + +export const KERNEL_MODELS: Kernel.IModel[] = [ + { + name: DEFAULT_NAME, + id: UUID.uuid4() + }, + { + name: 'r', + id: UUID.uuid4() + }, + { + name: DEFAULT_NAME, + id: UUID.uuid4() + } +]; + +// Notebook Paths for certain kernel name +export const NOTEBOOK_PATHS: { [kernelName: string]: string[] } = { + python3: ['Untitled.ipynb', 'Untitled1.ipynb', 'Untitled2.ipynb'], + r: ['Visualization.ipynb', 'Analysis.ipynb', 'Conclusion.ipynb'] +}; + +/** + * Clone a kernel connection. + */ +export function cloneKernel( + kernel: Kernel.IKernelConnection +): Kernel.IKernelConnection { + return (kernel as any).clone(); +} + +/** + * A mock kernel object. + * + * @param model The model of the kernel + */ +export const KernelMock = jest.fn< + Kernel.IKernelConnection, + [Private.RecursivePartial] +>(options => { + const model = { id: 'foo', name: DEFAULT_NAME, ...options.model }; + options = { + clientId: UUID.uuid4(), + username: UUID.uuid4(), + ...options, + model + }; + let executionCount = 0; + const spec = Private.kernelSpecForKernelName(model.name)!; + const thisObject: Kernel.IKernelConnection = { + ...jest.requireActual('@jupyterlab/services'), + ...options, + ...model, + model, + serverSettings: ServerConnection.makeSettings( + options.serverSettings as Partial + ), + status: 'idle', + spec: Promise.resolve(spec), + dispose: jest.fn(), + clone: jest.fn(() => { + const newKernel = Private.cloneKernel(options); + newKernel.iopubMessage.connect((_, args) => { + iopubMessageSignal.emit(args); + }); + newKernel.statusChanged.connect((_, args) => { + (thisObject as any).status = args; + statusChangedSignal.emit(args); + }); + return newKernel; + }), + info: Promise.resolve(Private.getInfo(model!.name!)), + shutdown: jest.fn(() => Promise.resolve(void 0)), + requestHistory: jest.fn(() => { + const historyReply = KernelMessage.createMessage({ + channel: 'shell', + msgType: 'history_reply', + session: options.clientId!, + username: options.username!, + content: { + history: [], + status: 'ok' + } + }); + return Promise.resolve(historyReply); + }), + restart: jest.fn(() => Promise.resolve(void 0)), + requestExecute: jest.fn(options => { + const msgId = UUID.uuid4(); + executionCount++; + Private.lastMessageProperty.set(thisObject, msgId); + const msg = KernelMessage.createMessage({ + channel: 'iopub', + msgType: 'execute_input', + session: thisObject.clientId, + username: thisObject.username, + msgId, + content: { + code: options.code, + execution_count: executionCount + } + }); + iopubMessageSignal.emit(msg); + const reply = KernelMessage.createMessage( + { + channel: 'shell', + msgType: 'execute_reply', + session: thisObject.clientId, + username: thisObject.username, + msgId, + content: { + user_expressions: {}, + execution_count: executionCount, + status: 'ok' + } + } + ); + return new MockShellFuture(reply) as Kernel.IShellFuture< + KernelMessage.IExecuteRequestMsg, + KernelMessage.IExecuteReplyMsg + >; + }) + }; + // Add signals. + const iopubMessageSignal = new Signal< + Kernel.IKernelConnection, + KernelMessage.IIOPubMessage + >(thisObject); + const statusChangedSignal = new Signal< + Kernel.IKernelConnection, + Kernel.Status + >(thisObject); + const pendingInputSignal = new Signal( + thisObject + ); + (thisObject as any).statusChanged = statusChangedSignal; + (thisObject as any).iopubMessage = iopubMessageSignal; + (thisObject as any).pendingInput = pendingInputSignal; + (thisObject as any).hasPendingInput = false; + return thisObject; +}); + +/** + * A mock session connection. + * + * @param options Addition session options to use + * @param model A session model to use + */ +export const SessionConnectionMock = jest.fn< + Session.ISessionConnection, + [ + Private.RecursivePartial, + Kernel.IKernelConnection | null + ] +>((options, kernel) => { + const name = kernel?.name || options.model?.kernel?.name || DEFAULT_NAME; + kernel = kernel || new KernelMock({ model: { name } }); + const model = { + id: UUID.uuid4(), + path: 'foo', + type: 'notebook', + name: 'foo', + ...options.model, + kernel: kernel!.model + }; + const thisObject: Session.ISessionConnection = { + ...jest.requireActual('@jupyterlab/services'), + ...options, + model, + ...model, + kernel, + serverSettings: ServerConnection.makeSettings( + options.serverSettings as Partial + ), + dispose: jest.fn(), + changeKernel: jest.fn(partialModel => { + return changeKernel(kernel!, partialModel!); + }), + shutdown: jest.fn(() => Promise.resolve(void 0)), + setPath: jest.fn(path => { + (thisObject as any).path = path; + propertyChangedSignal.emit('path'); + return Promise.resolve(); + }), + setName: jest.fn(name => { + (thisObject as any).name = name; + propertyChangedSignal.emit('name'); + return Promise.resolve(); + }), + setType: jest.fn(type => { + (thisObject as any).type = type; + propertyChangedSignal.emit('type'); + return Promise.resolve(); + }) + }; + const disposedSignal = new Signal( + thisObject + ); + const propertyChangedSignal = new Signal< + Session.ISessionConnection, + 'path' | 'name' | 'type' + >(thisObject); + const statusChangedSignal = new Signal< + Session.ISessionConnection, + Kernel.Status + >(thisObject); + const connectionStatusChangedSignal = new Signal< + Session.ISessionConnection, + Kernel.ConnectionStatus + >(thisObject); + const kernelChangedSignal = new Signal< + Session.ISessionConnection, + Session.ISessionConnection.IKernelChangedArgs + >(thisObject); + const iopubMessageSignal = new Signal< + Session.ISessionConnection, + KernelMessage.IIOPubMessage + >(thisObject); + + const unhandledMessageSignal = new Signal< + Session.ISessionConnection, + KernelMessage.IMessage + >(thisObject); + + const pendingInputSignal = new Signal( + thisObject + ); + + kernel!.iopubMessage.connect((_, args) => { + iopubMessageSignal.emit(args); + }, thisObject); + + kernel!.statusChanged.connect((_, args) => { + statusChangedSignal.emit(args); + }, thisObject); + + kernel!.pendingInput.connect((_, args) => { + pendingInputSignal.emit(args); + }, thisObject); + + (thisObject as any).disposed = disposedSignal; + (thisObject as any).connectionStatusChanged = connectionStatusChangedSignal; + (thisObject as any).propertyChanged = propertyChangedSignal; + (thisObject as any).statusChanged = statusChangedSignal; + (thisObject as any).kernelChanged = kernelChangedSignal; + (thisObject as any).iopubMessage = iopubMessageSignal; + (thisObject as any).unhandledMessage = unhandledMessageSignal; + (thisObject as any).pendingInput = pendingInputSignal; + return thisObject; +}); + +/** + * A mock contents manager. + */ +export const ContentsManagerMock = jest.fn(() => { + const files = new Map(); + const dummy = new ContentsManager(); + const checkpoints = new Map(); + const checkPointContent = new Map(); + + const baseModel = Private.createFile({ type: 'directory' }); + files.set('', { ...baseModel, path: '', name: '' }); + + const thisObject: Contents.IManager = { + ...jest.requireActual('@jupyterlab/services'), + newUntitled: jest.fn(options => { + const model = Private.createFile(options || {}); + files.set(model.path, model); + fileChangedSignal.emit({ + type: 'new', + oldValue: null, + newValue: model + }); + return Promise.resolve(model); + }), + createCheckpoint: jest.fn(path => { + const lastModified = new Date().toISOString(); + const data = { id: UUID.uuid4(), last_modified: lastModified }; + checkpoints.set(path, data); + checkPointContent.set(path, files.get(path)?.content); + return Promise.resolve(data); + }), + listCheckpoints: jest.fn(path => { + const p = checkpoints.get(path); + if (p !== undefined) { + return Promise.resolve([p]); + } + return Promise.resolve([]); + }), + deleteCheckpoint: jest.fn(path => { + if (!checkpoints.has(path)) { + return Private.makeResponseError(404); + } + checkpoints.delete(path); + return Promise.resolve(); + }), + restoreCheckpoint: jest.fn(path => { + if (!checkpoints.has(path)) { + return Private.makeResponseError(404); + } + (files.get(path) as any).content = checkPointContent.get(path); + return Promise.resolve(); + }), + getSharedModelFactory: jest.fn(() => { + return null; + }), + normalize: jest.fn(path => { + return dummy.normalize(path); + }), + localPath: jest.fn(path => { + return dummy.localPath(path); + }), + resolvePath: jest.fn((root, path) => { + return dummy.resolvePath(root, path); + }), + get: jest.fn((path, options) => { + path = Private.fixSlash(path); + if (!files.has(path)) { + return Private.makeResponseError(404); + } + const model = files.get(path)!; + if (model.type === 'directory') { + if (options?.content !== false) { + const content: Contents.IModel[] = []; + files.forEach(fileModel => { + if ( + // If file path is under this directory, add it to contents array. + PathExt.dirname(fileModel.path) == model.path && + // But the directory should exclude itself from the contents array. + fileModel !== model + ) { + content.push(fileModel); + } + }); + return Promise.resolve({ ...model, content }); + } + return Promise.resolve(model); + } + if (options?.content != false) { + return Promise.resolve(model); + } + return Promise.resolve({ ...model, content: '' }); + }), + driveName: jest.fn(path => { + return dummy.driveName(path); + }), + rename: jest.fn((oldPath, newPath) => { + oldPath = Private.fixSlash(oldPath); + newPath = Private.fixSlash(newPath); + if (!files.has(oldPath)) { + return Private.makeResponseError(404); + } + const oldValue = files.get(oldPath)!; + files.delete(oldPath); + const name = PathExt.basename(newPath); + const newValue = { ...oldValue, name, path: newPath }; + files.set(newPath, newValue); + fileChangedSignal.emit({ + type: 'rename', + oldValue, + newValue + }); + return Promise.resolve(newValue); + }), + delete: jest.fn(path => { + path = Private.fixSlash(path); + if (!files.has(path)) { + return Private.makeResponseError(404); + } + const oldValue = files.get(path)!; + files.delete(path); + fileChangedSignal.emit({ + type: 'delete', + oldValue, + newValue: null + }); + return Promise.resolve(void 0); + }), + save: jest.fn((path, options) => { + if (path == 'readonly.txt') { + return Private.makeResponseError(403); + } + path = Private.fixSlash(path); + const timeStamp = new Date().toISOString(); + if (files.has(path)) { + files.set(path, { + ...files.get(path)!, + ...options, + last_modified: timeStamp + }); + } else { + files.set(path, { + path, + name: PathExt.basename(path), + content: '', + writable: true, + created: timeStamp, + type: 'file', + format: 'text', + mimetype: 'plain/text', + ...options, + last_modified: timeStamp + }); + } + fileChangedSignal.emit({ + type: 'save', + oldValue: null, + newValue: files.get(path)! + }); + return Promise.resolve(files.get(path)!); + }), + getDownloadUrl: jest.fn(path => { + return dummy.getDownloadUrl(path); + }), + addDrive: jest.fn(drive => { + dummy.addDrive(drive); + }), + dispose: jest.fn() + }; + + const fileChangedSignal = new Signal< + Contents.IManager, + Contents.IChangedArgs + >(thisObject); + (thisObject as any).fileChanged = fileChangedSignal; + return thisObject; +}); + +/** + * A mock sessions manager. + */ +export const SessionManagerMock = jest.fn(() => { + let sessions: Session.IModel[] = []; + const thisObject: Session.IManager = { + ...jest.requireActual('@jupyterlab/services'), + ready: Promise.resolve(void 0), + isReady: true, + startNew: jest.fn(options => { + const session = new SessionConnectionMock({ model: options }, null); + sessions.push(session.model); + runningChangedSignal.emit(sessions); + return Promise.resolve(session); + }), + connectTo: jest.fn(options => { + return new SessionConnectionMock(options, null); + }), + stopIfNeeded: jest.fn(path => { + const length = sessions.length; + sessions = sessions.filter(model => model.path !== path); + if (sessions.length !== length) { + runningChangedSignal.emit(sessions); + } + return Promise.resolve(void 0); + }), + refreshRunning: jest.fn(() => Promise.resolve(void 0)), + running: jest.fn(() => sessions[Symbol.iterator]()) + }; + + const runningChangedSignal = new Signal( + thisObject + ); + (thisObject as any).runningChanged = runningChangedSignal; + return thisObject; +}); + +/** + * A mock kernel specs manager + */ +export const KernelSpecManagerMock = jest.fn(() => { + const thisObject: KernelSpec.IManager = { + ...jest.requireActual('@jupyterlab/services'), + specs: { default: DEFAULT_NAME, kernelspecs: KERNELSPECS }, + isReady: true, + ready: Promise.resolve(void 0), + refreshSpecs: jest.fn(() => Promise.resolve(void 0)) + }; + return thisObject; +}); + +/** + * A mock service manager. + */ +export const ServiceManagerMock = jest.fn(() => { + const thisObject: ServiceManager.IManager = { + ...jest.requireActual('@jupyterlab/services'), + ready: Promise.resolve(void 0), + isReady: true, + contents: new ContentsManagerMock(), + sessions: new SessionManagerMock(), + kernelspecs: new KernelSpecManagerMock(), + dispose: jest.fn() + }; + return thisObject; +}); + +/** + * A mock kernel shell future. + */ +export const MockShellFuture = jest.fn< + Kernel.IShellFuture, + [KernelMessage.IShellMessage] +>((result: KernelMessage.IShellMessage) => { + const thisObject: Kernel.IShellFuture = { + ...jest.requireActual('@jupyterlab/services'), + dispose: jest.fn(), + done: Promise.resolve(result) + }; + return thisObject; +}); + +export function changeKernel( + kernel: Kernel.IKernelConnection, + partialModel: Partial +): Promise { + if (partialModel.id) { + const kernelIdx = KERNEL_MODELS.findIndex(model => { + return model.id === partialModel.id; + }); + if (kernelIdx !== -1) { + (kernel.model as any) = Private.RUNNING_KERNELS[kernelIdx].model; + (kernel.id as any) = partialModel.id; + return Promise.resolve(Private.RUNNING_KERNELS[kernelIdx]); + } else { + throw new Error( + `Unable to change kernel to one with id: ${partialModel.id}` + ); + } + } else if (partialModel.name) { + const kernelIdx = KERNEL_MODELS.findIndex(model => { + return model.name === partialModel.name; + }); + if (kernelIdx !== -1) { + (kernel.model as any) = Private.RUNNING_KERNELS[kernelIdx].model; + (kernel.id as any) = partialModel.id; + return Promise.resolve(Private.RUNNING_KERNELS[kernelIdx]); + } else { + throw new Error( + `Unable to change kernel to one with name: ${partialModel.name}` + ); + } + } else { + throw new Error(`Unable to change kernel`); + } +} + +/** + * A namespace for module private data. + */ +namespace Private { + export type RecursivePartial = { + [P in keyof T]?: RecursivePartial; + }; + + export function createFile( + options?: Contents.ICreateOptions + ): Contents.IModel { + options = options || {}; + let name = UUID.uuid4(); + switch (options.type) { + case 'directory': + name = `Untitled Folder_${name}`; + break; + case 'notebook': + name = `Untitled_${name}.ipynb`; + break; + default: + name = `untitled_${name}${options.ext || '.txt'}`; + } + + const path = PathExt.join(options.path || '', name); + let content = ''; + if (options.type === 'notebook') { + content = JSON.stringify({}); + } + const timeStamp = new Date().toISOString(); + return { + path, + content, + name, + last_modified: timeStamp, + writable: true, + created: timeStamp, + type: options.type || 'file', + format: 'text', + mimetype: 'plain/text' + }; + } + + export function fixSlash(path: string): string { + if (path.endsWith('/')) { + path = path.slice(0, path.length - 1); + } + return path; + } + + export function makeResponseError(status: number): Promise { + const resp = new Response(void 0, { status }); + return Promise.reject(new ServerConnection.ResponseError(resp)); + } + + export function cloneKernel( + options: RecursivePartial + ): Kernel.IKernelConnection { + return new KernelMock({ ...options, clientId: UUID.uuid4() }); + } + + // Get the kernel spec for kernel name + export function kernelSpecForKernelName(name: string): KernelSpec.ISpecModel { + return KERNELSPECS[name]; + } + + // Get the kernel info for kernel name + export function getInfo(name: string): KernelMessage.IInfoReply { + return { + protocol_version: '1', + implementation: 'foo', + implementation_version: '1', + language_info: { + version: '1', + name + }, + banner: 'hello, world!', + help_links: [], + status: 'ok' + }; + } + + // This list of running kernels simply mirrors the KERNEL_MODELS and KERNELSPECS lists + export const RUNNING_KERNELS: Kernel.IKernelConnection[] = KERNEL_MODELS.map( + (model, _) => { + return new KernelMock({ model }); + } + ); + + export const lastMessageProperty = new AttachedProperty< + Kernel.IKernelConnection, + string + >({ + name: 'lastMessageId', + create: () => '' + }); +} + +/** + * The user API service manager. + */ +export class FakeUserManager extends BaseManager implements User.IManager { + private _isReady = false; + private _ready: Promise; + + private _identity: User.IIdentity; + private _permissions: ReadonlyJSONObject; + + private _userChanged = new Signal(this); + private _connectionFailure = new Signal(this); + + /** + * Create a new user manager. + */ + constructor( + options: UserManager.IOptions = {}, + identity: User.IIdentity, + permissions: ReadonlyJSONObject + ) { + super(options); + + // Initialize internal data. + this._ready = new Promise(resolve => { + // Schedule updating the user to the next macro task queue. + setTimeout(() => { + this._identity = identity; + this._permissions = permissions; + + this._userChanged.emit({ + identity: this._identity, + permissions: this._permissions as PartialJSONObject + }); + + resolve(); + }, 0); + }) + .then(() => { + if (this.isDisposed) { + return; + } + this._isReady = true; + }) + .catch(_ => undefined); + } + + /** + * The server settings for the manager. + */ + readonly serverSettings: ServerConnection.ISettings; + + /** + * Test whether the manager is ready. + */ + get isReady(): boolean { + return this._isReady; + } + + /** + * A promise that fulfills when the manager is ready. + */ + get ready(): Promise { + return this._ready; + } + + /** + * Get the most recently fetched identity. + */ + get identity(): User.IIdentity | null { + return this._identity; + } + + /** + * Get the most recently fetched permissions. + */ + get permissions(): ReadonlyJSONObject | null { + return this._permissions; + } + + /** + * A signal emitted when the user changes. + */ + get userChanged(): ISignal { + return this._userChanged; + } + + /** + * A signal emitted when there is a connection failure. + */ + get connectionFailure(): ISignal { + return this._connectionFailure; + } + + /** + * Dispose of the resources used by the manager. + */ + dispose(): void { + super.dispose(); + } + + /** + * Force a refresh of the specs from the server. + * + * @returns A promise that resolves when the specs are fetched. + * + * #### Notes + * This is intended to be called only in response to a user action, + * since the manager maintains its internal state. + */ + async refreshUser(): Promise { + return Promise.resolve(); + } +} diff --git a/packages/services/src/user/index.ts b/packages/services/src/user/index.ts index 0e4cffaf99db..deefd8c06f4a 100644 --- a/packages/services/src/user/index.ts +++ b/packages/services/src/user/index.ts @@ -60,6 +60,7 @@ export class UserManager extends BaseManager implements User.IManager { .catch( _ => // Return a promise that will never resolve, so user service is never ready + // This typically occurs when the backend has no user service new Promise(() => { // no-op }) diff --git a/packages/services/src/validate.ts b/packages/services/src/validate.ts index cd48678c1c6c..ad07982ebfb2 100644 --- a/packages/services/src/validate.ts +++ b/packages/services/src/validate.ts @@ -6,6 +6,7 @@ * of a given type and among a given set of values. */ export function validateProperty( + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types object: any, name: string, typeName?: string, diff --git a/packages/services/test/config/config.spec.ts b/packages/services/test/config/config.spec.ts index 22fe9d8da4e5..fb052861f599 100644 --- a/packages/services/test/config/config.spec.ts +++ b/packages/services/test/config/config.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { expectFailure, JupyterServer } from '@jupyterlab/testutils'; +import { expectFailure, JupyterServer } from '@jupyterlab/testing'; import { JSONObject, UUID } from '@lumino/coreutils'; import { ConfigSection, ConfigWithDefaults } from '../../src'; import { getRequestHandler, handleRequest, makeSettings } from '../utils'; @@ -22,7 +22,7 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); @@ -50,7 +50,9 @@ describe('config', () => { name: randomName(), serverSettings }); - await expectFailure(configPromise, 'Invalid response: 201 Created'); + await expect(configPromise).rejects.toThrow( + /Invalid response: 201 Created/ + ); }); }); @@ -81,7 +83,7 @@ describe('config', () => { const config = await ConfigSection.create({ name: randomName() }); handleRequest(config, 201, {}); const update = config.update({ foo: 'baz' }); - await expectFailure(update, 'Invalid response: 201 Created'); + await expect(update).rejects.toThrow(/Invalid response: 201 Created/); }); }); }); diff --git a/packages/services/test/contents/index.spec.ts b/packages/services/test/contents/index.spec.ts index ab4ea8ddeff3..9782f2ed5ead 100644 --- a/packages/services/test/contents/index.spec.ts +++ b/packages/services/test/contents/index.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { expectFailure, JupyterServer } from '@jupyterlab/testutils'; +import { expectFailure, JupyterServer } from '@jupyterlab/testing'; import { Contents, ContentsManager, Drive, ServerConnection } from '../../src'; import { DEFAULT_FILE, handleRequest, makeSettings } from '../utils'; @@ -29,7 +29,7 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); @@ -110,10 +110,10 @@ describe('contents', () => { }); describe('#addDrive()', () => { - it('should add a new drive to the manager', () => { + it('should add a new drive to the manager', async () => { contents.addDrive(new Drive({ name: 'other' })); handleRequest(contents, 200, DEFAULT_FILE); - return contents.get('other:'); + await expect(contents.get('other:')).resolves.not.toThrow(); }); }); @@ -260,7 +260,25 @@ describe('contents', () => { it('should fail for an incorrect response', async () => { handleRequest(contents, 201, DEFAULT_DIR); const get = contents.get('/foo'); - await expectFailure(get, 'Invalid response: 201 Created'); + await expect(get).rejects.toThrow(/Invalid response: 201 Created/); + }); + + it('should store original server path for directory', async () => { + const drive = new Drive({ name: 'other', serverSettings }); + contents.addDrive(drive); + handleRequest(drive, 200, DEFAULT_DIR); + const options: Contents.IFetchOptions = { type: 'directory' }; + const model = await contents.get('other:/foo', options); + expect(model.serverPath).toBe('foo/bar'); + }); + + it('should store original server path for a file', async () => { + const drive = new Drive({ name: 'other', serverSettings }); + contents.addDrive(drive); + handleRequest(drive, 200, DEFAULT_FILE); + const options: Contents.IFetchOptions = { type: 'file' }; + const model = await contents.get('other:/foo', options); + expect(model.serverPath).toBe('foo/test'); }); it('should store original server path for directory', async () => { @@ -387,27 +405,29 @@ describe('contents', () => { ext: 'py' }; const newFile = contents.newUntitled(options); - await expectFailure(newFile); + await expect(newFile).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { handleRequest(contents, 200, DEFAULT_DIR); const newDir = contents.newUntitled(); - await expectFailure(newDir, 'Invalid response: 200 OK'); + await expect(newDir).rejects.toThrow(/Invalid response: 200 OK/); }); }); describe('#delete()', () => { - it('should delete a file', () => { + it('should delete a file', async () => { handleRequest(contents, 204, {}); - return contents.delete('/foo/bar.txt'); + await expect(contents.delete('/foo/bar.txt')).resolves.not.toThrow(); }); - it('should delete a file on an additional drive', () => { + it('should delete a file on an additional drive', async () => { const other = new Drive({ name: 'other', serverSettings }); contents.addDrive(other); handleRequest(other, 204, {}); - return contents.delete('other:/foo/bar.txt'); + await expect( + contents.delete('other:/foo/bar.txt') + ).resolves.not.toThrow(); }); it('should emit the fileChanged signal', async () => { @@ -426,19 +446,19 @@ describe('contents', () => { it('should fail for an incorrect response', async () => { handleRequest(contents, 200, {}); const del = contents.delete('/foo/bar.txt'); - await expectFailure(del, 'Invalid response: 200 OK'); + await expect(del).rejects.toThrow(/Invalid response: 200 OK/); }); it('should throw a specific error', async () => { handleRequest(contents, 400, {}); const del = contents.delete('/foo/'); - await expectFailure(del, ''); + await expect(del).rejects.toThrow(); }); it('should throw a general error', async () => { handleRequest(contents, 500, {}); const del = contents.delete('/foo/'); - await expectFailure(del, ''); + await expect(del).rejects.toThrow(); }); }); @@ -480,13 +500,13 @@ describe('contents', () => { delete dir.path; handleRequest(contents, 200, dir); const rename = contents.rename('/foo/bar.txt', '/foo/baz.txt'); - await expectFailure(rename); + await expect(rename).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { handleRequest(contents, 201, DEFAULT_FILE); const rename = contents.rename('/foo/bar.txt', '/foo/baz.txt'); - await expectFailure(rename, 'Invalid response: 201 Created'); + await expect(rename).rejects.toThrow(/Invalid response: 201 Created/); }); }); @@ -532,13 +552,13 @@ describe('contents', () => { delete file.format; handleRequest(contents, 200, file); const save = contents.save('/foo', { type: 'file', name: 'test' }); - await expectFailure(save); + await expect(save).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { handleRequest(contents, 204, DEFAULT_FILE); const save = contents.save('/foo', { type: 'file', name: 'test' }); - await expectFailure(save, 'Invalid response: 204 No Content'); + await expect(save).rejects.toThrow(/Invalid response: 204 No Content/); }); }); @@ -575,13 +595,13 @@ describe('contents', () => { delete file.type; handleRequest(contents, 201, file); const copy = contents.copy('/foo/bar.txt', '/baz'); - await expectFailure(copy); + await expect(copy).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { handleRequest(contents, 200, DEFAULT_FILE); const copy = contents.copy('/foo/bar.txt', '/baz'); - await expectFailure(copy, 'Invalid response: 200 OK'); + await expect(copy).rejects.toThrow(/Invalid response: 200 OK/); }); }); @@ -607,13 +627,13 @@ describe('contents', () => { delete cp.last_modified; handleRequest(contents, 201, cp); const checkpoint = contents.createCheckpoint('/foo/bar.txt'); - await expectFailure(checkpoint); + await expect(checkpoint).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { handleRequest(contents, 200, DEFAULT_CP); const checkpoint = contents.createCheckpoint('/foo/bar.txt'); - await expectFailure(checkpoint, 'Invalid response: 200 OK'); + await expect(checkpoint).rejects.toThrow(/Invalid response: 200 OK/); }); }); @@ -642,27 +662,29 @@ describe('contents', () => { await expectFailure(checkpoints); handleRequest(contents, 200, DEFAULT_CP); const newCheckpoints = contents.listCheckpoints('/foo/bar.txt'); - await expectFailure(newCheckpoints, 'Invalid Checkpoint list'); + await expect(newCheckpoints).rejects.toThrow(/Invalid Checkpoint list/); }); it('should fail for an incorrect response', async () => { handleRequest(contents, 201, {}); const checkpoints = contents.listCheckpoints('/foo/bar.txt'); - await expectFailure(checkpoints, 'Invalid response: 201 Created'); + await expect(checkpoints).rejects.toThrow( + /Invalid response: 201 Created/ + ); }); }); describe('#restoreCheckpoint()', () => { - it('should restore a checkpoint', () => { + it('should restore a checkpoint', async () => { handleRequest(contents, 204, {}); const checkpoint = contents.restoreCheckpoint( '/foo/bar.txt', DEFAULT_CP.id ); - return checkpoint; + await expect(checkpoint).resolves.not.toThrow(); }); - it('should restore a checkpoint on an additional drive', () => { + it('should restore a checkpoint on an additional drive', async () => { const other = new Drive({ name: 'other', serverSettings }); contents.addDrive(other); handleRequest(other, 204, {}); @@ -670,7 +692,7 @@ describe('contents', () => { 'other:/foo/bar.txt', DEFAULT_CP.id ); - return checkpoint; + await expect(checkpoint).resolves.not.toThrow(); }); it('should fail for an incorrect response', async () => { @@ -679,21 +701,25 @@ describe('contents', () => { '/foo/bar.txt', DEFAULT_CP.id ); - await expectFailure(checkpoint, 'Invalid response: 200 OK'); + await expect(checkpoint).rejects.toThrow(/Invalid response: 200 OK/); }); }); describe('#deleteCheckpoint()', () => { - it('should delete a checkpoint', () => { + it('should delete a checkpoint', async () => { handleRequest(contents, 204, {}); - return contents.deleteCheckpoint('/foo/bar.txt', DEFAULT_CP.id); + await expect( + contents.deleteCheckpoint('/foo/bar.txt', DEFAULT_CP.id) + ).resolves.not.toThrow(); }); - it('should delete a checkpoint on an additional drive', () => { + it('should delete a checkpoint on an additional drive', async () => { const other = new Drive({ name: 'other', serverSettings }); contents.addDrive(other); handleRequest(other, 204, {}); - return contents.deleteCheckpoint('other:/foo/bar.txt', DEFAULT_CP.id); + await expect( + contents.deleteCheckpoint('other:/foo/bar.txt', DEFAULT_CP.id) + ).resolves.not.toThrow(); }); it('should fail for an incorrect response', async () => { @@ -702,7 +728,7 @@ describe('contents', () => { '/foo/bar.txt', DEFAULT_CP.id ); - await expectFailure(checkpoint, 'Invalid response: 200 OK'); + await expect(checkpoint).rejects.toThrow(/Invalid response: 200 OK/); }); }); }); @@ -813,7 +839,7 @@ describe('drive', () => { const drive = new Drive(); handleRequest(drive, 201, DEFAULT_DIR); const get = drive.get('/foo'); - await expectFailure(get, 'Invalid response: 201 Created'); + await expect(get).rejects.toThrow(/Invalid response: 201 Created/); }); }); @@ -903,14 +929,14 @@ describe('drive', () => { ext: 'py' }; const newFile = drive.newUntitled(options); - await expectFailure(newFile); + await expect(newFile).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 200, DEFAULT_DIR); const newDir = drive.newUntitled(); - await expectFailure(newDir, 'Invalid response: 200 OK'); + await expect(newDir).rejects.toThrow(/Invalid response: 200 OK/); }); }); @@ -918,7 +944,7 @@ describe('drive', () => { it('should delete a file', async () => { const drive = new Drive(); handleRequest(drive, 204, {}); - await drive.delete('/foo/bar.txt'); + await expect(drive.delete('/foo/bar.txt')).resolves.not.toThrow(); }); it('should emit the fileChanged signal', async () => { @@ -938,28 +964,28 @@ describe('drive', () => { it('should accept server settings', async () => { const drive = new Drive({ serverSettings }); handleRequest(drive, 204, {}); - await drive.delete('/foo/bar.txt'); + await expect(drive.delete('/foo/bar.txt')).resolves.not.toThrow(); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 200, {}); const del = drive.delete('/foo/bar.txt'); - await expectFailure(del, 'Invalid response: 200 OK'); + await expect(del).rejects.toThrow(/Invalid response: 200 OK/); }); it('should throw a specific error', async () => { const drive = new Drive(); handleRequest(drive, 400, {}); const del = drive.delete('/foo/'); - await expectFailure(del, ''); + await expect(del).rejects.toThrow(); }); it('should throw a general error', async () => { const drive = new Drive(); handleRequest(drive, 500, {}); const del = drive.delete('/foo/'); - await expectFailure(del, ''); + await expect(del).rejects.toThrow(); }); }); @@ -1000,14 +1026,14 @@ describe('drive', () => { delete dir.path; handleRequest(drive, 200, dir); const rename = drive.rename('/foo/bar.txt', '/foo/baz.txt'); - await expectFailure(rename); + await expect(rename).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 201, DEFAULT_FILE); const rename = drive.rename('/foo/bar.txt', '/foo/baz.txt'); - await expectFailure(rename, 'Invalid response: 201 Created'); + await expect(rename).rejects.toThrow(/Invalid response: 201 Created/); }); }); @@ -1056,14 +1082,14 @@ describe('drive', () => { delete file.format; handleRequest(drive, 200, file); const save = drive.save('/foo', { type: 'file', name: 'test' }); - await expectFailure(save); + await expect(save).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 204, DEFAULT_FILE); const save = drive.save('/foo', { type: 'file', name: 'test' }); - await expectFailure(save, 'Invalid response: 204 No Content'); + await expect(save).rejects.toThrow(/Invalid response: 204 No Content/); }); }); @@ -1102,14 +1128,14 @@ describe('drive', () => { delete file.type; handleRequest(drive, 201, file); const copy = drive.copy('/foo/bar.txt', '/baz'); - await expectFailure(copy); + await expect(copy).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 200, DEFAULT_FILE); const copy = drive.copy('/foo/bar.txt', '/baz'); - await expectFailure(copy, 'Invalid response: 200 OK'); + await expect(copy).rejects.toThrow(/Invalid response: 200 OK/); }); }); @@ -1136,14 +1162,14 @@ describe('drive', () => { delete cp.last_modified; handleRequest(drive, 201, cp); const checkpoint = drive.createCheckpoint('/foo/bar.txt'); - await expectFailure(checkpoint); + await expect(checkpoint).rejects.toThrow(); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 200, DEFAULT_CP); const checkpoint = drive.createCheckpoint('/foo/bar.txt'); - await expectFailure(checkpoint, 'Invalid response: 200 OK'); + await expect(checkpoint).rejects.toThrow(/Invalid response: 200 OK/); }); }); @@ -1173,58 +1199,64 @@ describe('drive', () => { await expectFailure(checkpoints); handleRequest(drive, 200, DEFAULT_CP); const newCheckpoints = drive.listCheckpoints('/foo/bar.txt'); - await expectFailure(newCheckpoints, 'Invalid Checkpoint list'); + await expect(newCheckpoints).rejects.toThrow(/Invalid Checkpoint list/); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 201, {}); const checkpoints = drive.listCheckpoints('/foo/bar.txt'); - await expectFailure(checkpoints, 'Invalid response: 201 Created'); + await expect(checkpoints).rejects.toThrow( + /Invalid response: 201 Created/ + ); }); }); describe('#restoreCheckpoint()', () => { - it('should restore a checkpoint', () => { + it('should restore a checkpoint', async () => { const drive = new Drive(); handleRequest(drive, 204, {}); const checkpoint = drive.restoreCheckpoint('/foo/bar.txt', DEFAULT_CP.id); - return checkpoint; + await expect(checkpoint).resolves.not.toThrow(); }); - it('should accept server settings', () => { + it('should accept server settings', async () => { const drive = new Drive({ serverSettings }); handleRequest(drive, 204, {}); const checkpoint = drive.restoreCheckpoint('/foo/bar.txt', DEFAULT_CP.id); - return checkpoint; + await expect(checkpoint).resolves.not.toThrow(); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 200, {}); const checkpoint = drive.restoreCheckpoint('/foo/bar.txt', DEFAULT_CP.id); - await expectFailure(checkpoint, 'Invalid response: 200 OK'); + await expect(checkpoint).rejects.toThrow(/Invalid response: 200 OK/); }); }); describe('#deleteCheckpoint()', () => { - it('should delete a checkpoint', () => { + it('should delete a checkpoint', async () => { const drive = new Drive(); handleRequest(drive, 204, {}); - return drive.deleteCheckpoint('/foo/bar.txt', DEFAULT_CP.id); + await expect( + drive.deleteCheckpoint('/foo/bar.txt', DEFAULT_CP.id) + ).resolves.not.toThrow(); }); - it('should accept server settings', () => { + it('should accept server settings', async () => { const drive = new Drive({ serverSettings }); handleRequest(drive, 204, {}); - return drive.deleteCheckpoint('/foo/bar.txt', DEFAULT_CP.id); + await expect( + drive.deleteCheckpoint('/foo/bar.txt', DEFAULT_CP.id) + ).resolves.not.toThrow(); }); it('should fail for an incorrect response', async () => { const drive = new Drive(); handleRequest(drive, 200, {}); const checkpoint = drive.deleteCheckpoint('/foo/bar.txt', DEFAULT_CP.id); - await expectFailure(checkpoint, 'Invalid response: 200 OK'); + await expect(checkpoint).rejects.toThrow(/Invalid response: 200 OK/); }); }); @@ -1239,6 +1271,7 @@ describe('drive', () => { if (content[i].type === 'file') { path = content[i].path; const msg = await contents.get(path, { type: 'file' }); + // eslint-disable-next-line jest/no-conditional-expect expect(msg.path).toBe(path); called = true; } @@ -1261,7 +1294,7 @@ describe('drive', () => { format: 'text' }; await contents.save('baz.txt', options); - await contents.delete('baz.txt'); + await expect(contents.delete('baz.txt')).resolves.not.toThrow(); }); it('should exercise the checkpoint API', async () => { diff --git a/packages/services/test/contents/validate.spec.ts b/packages/services/test/contents/validate.spec.ts index 28c81698f373..3f546751c986 100644 --- a/packages/services/test/contents/validate.spec.ts +++ b/packages/services/test/contents/validate.spec.ts @@ -10,35 +10,39 @@ import { DEFAULT_FILE } from '../utils'; describe('validate', () => { describe('validateContentsModel()', () => { it('should pass with valid data', () => { - validateContentsModel(DEFAULT_FILE); + expect(() => { + validateContentsModel(DEFAULT_FILE); + }).not.toThrow(); }); it('should fail on missing data', () => { const model = JSON.parse(JSON.stringify(DEFAULT_FILE)); delete model['path']; - expect(() => validateContentsModel(model)).toThrowError(); + expect(() => validateContentsModel(model)).toThrow(); }); it('should fail on incorrect data', () => { const model = JSON.parse(JSON.stringify(DEFAULT_FILE)); model.type = 1; - expect(() => validateContentsModel(model)).toThrowError(); + expect(() => validateContentsModel(model)).toThrow(); }); }); describe('validateCheckpointModel()', () => { it('should pass with valid data', () => { - validateCheckpointModel({ id: 'foo', last_modified: 'yesterday ' }); + expect(() => { + validateCheckpointModel({ id: 'foo', last_modified: 'yesterday ' }); + }).not.toThrow(); }); it('should fail on missing data', () => { const model = { id: 'foo' }; - expect(() => validateCheckpointModel(model as any)).toThrowError(); + expect(() => validateCheckpointModel(model as any)).toThrow(); }); it('should fail on incorrect data', () => { const model = { id: 1, last_modified: '1' }; - expect(() => validateCheckpointModel(model as any)).toThrowError(); + expect(() => validateCheckpointModel(model as any)).toThrow(); }); }); }); diff --git a/packages/services/test/event/manager.spec.ts b/packages/services/test/event/manager.spec.ts new file mode 100644 index 000000000000..8eaa3cc9d554 --- /dev/null +++ b/packages/services/test/event/manager.spec.ts @@ -0,0 +1,138 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { JupyterServer } from '@jupyterlab/testing'; +import { PromiseDelegate } from '@lumino/coreutils'; +import { EventManager, ServerConnection } from '../../src'; + +describe('setting', () => { + let server: JupyterServer; + + beforeAll(async () => { + server = new JupyterServer(); + await server.start(); + }, 30000); + + afterAll(async () => { + await server.shutdown(); + }); + + describe('EventManager', () => { + let manager: EventManager; + + beforeEach(() => { + manager = new EventManager({ + serverSettings: ServerConnection.makeSettings({ appUrl: 'lab' }) + }); + }); + + afterEach(() => { + manager.dispose(); + }); + + describe('#constructor()', () => { + it('should accept no options', () => { + const manager = new EventManager(); + expect(manager).toBeInstanceOf(EventManager); + }); + + it('should accept options', () => { + const manager = new EventManager({ + serverSettings: ServerConnection.makeSettings() + }); + expect(manager).toBeInstanceOf(EventManager); + }); + }); + + describe('#serverSettings', () => { + it('should be the server settings', () => { + const baseUrl = 'http://localhost/foo'; + const serverSettings = ServerConnection.makeSettings({ baseUrl }); + const manager = new EventManager({ serverSettings }); + expect(manager.serverSettings.baseUrl).toBe(baseUrl); + }); + }); + + describe('#stream[Symbol.asyncIterator]()', () => { + it('should yield an event', async () => { + const delegate = new PromiseDelegate(); + const expected = `#stream[Symbol.asyncIterator]() test`; + let received = ''; + setTimeout(async () => { + for await (const emission of manager.stream) { + received = (emission.path as string) || ''; + if (received === expected) { + break; + } + } + expect(received).toEqual(expected); + delegate.resolve(); + }); + setTimeout(() => { + void manager.emit({ + // eslint-disable-next-line camelcase + schema_id: + 'https://events.jupyter.org/jupyter_server/contents_service/v1', + data: { action: 'get', path: expected }, + version: '1' + }); + }, 500); + return delegate.promise; + }); + }); + + describe('#stream.connect()', () => { + it('should yield an event', async () => { + const delegate = new PromiseDelegate(); + const expected = `#stream.connect() test`; + let received = ''; + manager.stream.connect((_, emission) => { + received = (emission.path as string) || ''; + if (received !== expected) { + return; + } + expect(received).toEqual(expected); + delegate.resolve(); + }); + setTimeout(() => { + void manager.emit({ + // eslint-disable-next-line camelcase + schema_id: + 'https://events.jupyter.org/jupyter_server/contents_service/v1', + data: { action: 'get', path: expected }, + version: '1' + }); + }, 500); + return delegate.promise; + }); + }); + + describe('#emit()', () => { + it('should emit an event', async () => { + const delegate = new PromiseDelegate(); + const expected = `#emit() test`; + let received = ''; + setTimeout(async () => { + for await (const emission of manager.stream) { + received = (emission.path as string) || ''; + if (received === expected) { + break; + } + } + expect(received).toEqual(expected); + delegate.resolve(); + }); + setTimeout(() => { + void manager.emit({ + // eslint-disable-next-line camelcase + schema_id: + 'https://events.jupyter.org/jupyter_server/contents_service/v1', + data: { action: 'get', path: expected }, + version: '1' + }); + }, 500); + return delegate.promise; + }); + }); + }); +}); diff --git a/packages/services/test/kernel/comm.spec.ts b/packages/services/test/kernel/comm.spec.ts index 456c49afef92..424f81f2af7b 100644 --- a/packages/services/test/kernel/comm.spec.ts +++ b/packages/services/test/kernel/comm.spec.ts @@ -1,11 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { - isFulfilled, - flakyIt as it, - JupyterServer -} from '@jupyterlab/testutils'; +import { isFulfilled, JupyterServer } from '@jupyterlab/testing'; import { PromiseDelegate } from '@lumino/coreutils'; import { Kernel, KernelManager, KernelMessage } from '../../src'; @@ -42,25 +38,19 @@ def target_func(comm, msg): get_ipython().kernel.comm_manager.register_target("test", target_func) `; -const server = new JupyterServer(); - -beforeAll(async () => { - await server.start(); -}); - -afterAll(async () => { - await server.shutdown(); -}); - describe('jupyter.services - Comm', () => { + let server: JupyterServer; let kernelManager: KernelManager; let kernel: Kernel.IKernelConnection; + jest.retryTimes(3); + beforeAll(async () => { - jest.setTimeout(20000); + server = new JupyterServer(); + await server.start(); kernelManager = new KernelManager(); kernel = await kernelManager.startNew({ name: 'ipython' }); - }); + }, 30000); afterEach(() => { // A no-op comm target. @@ -71,6 +61,7 @@ describe('jupyter.services - Comm', () => { afterAll(async () => { await kernel.shutdown(); + await server.shutdown(); }); describe('Kernel', () => { @@ -88,7 +79,7 @@ describe('jupyter.services - Comm', () => { }); it('should throw an error if there is an existing comm', () => { - expect(() => kernel.createComm('test', '1234')).toThrowError(); + expect(() => kernel.createComm('test', '1234')).toThrow(); }); it('should throw an error when the kernel does not handle comms', async () => { @@ -97,7 +88,7 @@ describe('jupyter.services - Comm', () => { { handleComms: false } ); expect(kernel2.handleComms).toBe(false); - expect(() => kernel2.createComm('test', '1234')).toThrowError(); + expect(() => kernel2.createComm('test', '1234')).toThrow(); }); }); @@ -274,7 +265,7 @@ describe('jupyter.services - Comm', () => { comm.send('quit'); }); await kernel.requestExecute({ code: SEND }, true).done; - await promise.promise; + await expect(promise.promise).resolves.not.toThrow(); }); }); @@ -322,7 +313,7 @@ describe('jupyter.services - Comm', () => { data, data.buffer ]); - await future2.done; + await expect(future2.done).resolves.not.toThrow(); }); }); @@ -330,13 +321,13 @@ describe('jupyter.services - Comm', () => { it('should send a message to the server', async () => { await comm.open().done; const future = comm.send({ foo: 'bar' }, { fizz: 'buzz' }); - await future.done; + await expect(future.done).resolves.not.toThrow(); }); it('should pass through a buffers field', async () => { await comm.open().done; const future = comm.send({ buffers: 'bar' }); - await future.done; + await expect(future.done).resolves.not.toThrow(); }); }); @@ -346,7 +337,7 @@ describe('jupyter.services - Comm', () => { const encoder = new TextEncoder(); const data = encoder.encode('hello'); const future = comm.close({ foo: 'bar' }, {}, [data, data.buffer]); - await future.done; + await expect(future.done).resolves.not.toThrow(); }); it('should trigger an onClose', async () => { @@ -366,7 +357,7 @@ describe('jupyter.services - Comm', () => { await comm.close({ foo: 'bar' }).done; expect(() => { comm.send('test'); - }).toThrowError(); + }).toThrow(); }); }); }); diff --git a/packages/services/test/kernel/ifuture.spec.ts b/packages/services/test/kernel/ifuture.spec.ts index 379e3d510e15..77962e80f058 100644 --- a/packages/services/test/kernel/ifuture.spec.ts +++ b/packages/services/test/kernel/ifuture.spec.ts @@ -1,27 +1,22 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { flakyIt as it, JupyterServer } from '@jupyterlab/testutils'; +import { JupyterServer } from '@jupyterlab/testing'; import { Kernel, KernelAPI, KernelManager, KernelMessage } from '../../src'; import { KernelTester } from '../utils'; -const server = new JupyterServer(); - -beforeAll(async () => { - await server.start(); -}); - -afterAll(async () => { - await server.shutdown(); -}); - describe('Kernel.IShellFuture', () => { + let server: JupyterServer; let tester: KernelTester; let kernelManager: KernelManager; - beforeAll(() => { + jest.retryTimes(3); + + beforeAll(async () => { + server = new JupyterServer(); + await server.start(); kernelManager = new KernelManager(); - }); + }, 30000); afterEach(() => { if (tester) { @@ -32,6 +27,7 @@ describe('Kernel.IShellFuture', () => { afterAll(async () => { const models = await KernelAPI.listRunning(); await Promise.all(models.map(m => KernelAPI.shutdownKernel(m.id))); + await server.shutdown(); }); it('should have a msg attribute', async () => { @@ -105,8 +101,10 @@ describe('Kernel.IShellFuture', () => { calls.push('first'); // Check to make sure we actually got the messages we expected. if (msg.header.msg_type === 'stream') { + // eslint-disable-next-line jest/no-conditional-expect expect((msg as KernelMessage.IStreamMsg).content.text).toBe('foo'); } else { + // eslint-disable-next-line jest/no-conditional-expect expect( (msg as KernelMessage.IStatusMsg).content.execution_state ).toBe('idle'); diff --git a/packages/services/test/kernel/ikernel.spec.ts b/packages/services/test/kernel/ikernel.spec.ts index 62cf0593f989..26de78d7e063 100644 --- a/packages/services/test/kernel/ikernel.spec.ts +++ b/packages/services/test/kernel/ikernel.spec.ts @@ -2,12 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { PageConfig } from '@jupyterlab/coreutils'; -import { - expectFailure, - flakyIt as it, - JupyterServer, - testEmission -} from '@jupyterlab/testutils'; +import { JupyterServer, testEmission } from '@jupyterlab/testing'; import { PromiseDelegate, UUID } from '@lumino/coreutils'; import { Kernel, @@ -18,26 +13,20 @@ import { } from '../../src'; import { FakeKernelManager, handleRequest, KernelTester } from '../utils'; -const server = new JupyterServer(); - -beforeAll(async () => { - await server.start(); -}); - -afterAll(async () => { - await server.shutdown(); -}); - describe('Kernel.IKernel', () => { let defaultKernel: Kernel.IKernelConnection; let specs: KernelSpec.ISpecModels; let kernelManager: KernelManager; + let server: JupyterServer; + + jest.retryTimes(3); beforeAll(async () => { - jest.setTimeout(20000); + server = new JupyterServer(); + await server.start(); kernelManager = new FakeKernelManager(); specs = await KernelSpecAPI.getSpecs(); - }); + }, 30000); beforeEach(async () => { defaultKernel = await kernelManager.startNew(); @@ -51,6 +40,7 @@ describe('Kernel.IKernel', () => { afterAll(async () => { await kernelManager.shutdownAll(); + await server.shutdown(); }); describe('#disposed', () => { @@ -121,25 +111,6 @@ describe('Kernel.IKernel', () => { ).done; expect(called).toBe(true); }); - - it('should be a signal following input request without parent header', async () => { - let called = false; - defaultKernel.pendingInput.connect((sender, args) => { - if (!called) { - called = true; - defaultKernel.sendInputReply({ status: 'ok', value: 'foo' }); - } - }); - const code = `input("Input something")`; - await defaultKernel.requestExecute( - { - code: code, - allow_stdin: true - }, - true - ).done; - expect(called).toBe(true); - }); }); describe('#iopubMessage', () => { @@ -170,7 +141,7 @@ describe('Kernel.IKernel', () => { }); tester.send(msg); await emission; - await tester.shutdown(); + await expect(tester.shutdown()).resolves.not.toThrow(); tester.dispose(); }); }); @@ -198,9 +169,9 @@ describe('Kernel.IKernel', () => { msgId, content: {} }); - msg.parent_header = { session: kernel.clientId }; + msg.parent_header = { session: kernel.clientId } as any; tester.send(msg); - await emission; + await expect(emission).resolves.not.toThrow(); }); it('should not be emitted for an iopub signal', async () => { @@ -226,7 +197,7 @@ describe('Kernel.IKernel', () => { msgId, content: {} }); - msg.parent_header = { session: kernel.clientId }; + msg.parent_header = { session: kernel.clientId } as any; tester.send(msg); await emission; @@ -256,7 +227,7 @@ describe('Kernel.IKernel', () => { msgId: 'message from wrong session', content: {} }); - msg1.parent_header = { session: 'wrong session' }; + msg1.parent_header = { session: 'wrong session' } as any; tester.send(msg1); // Send a shell message with the right client (parent) session. @@ -267,7 +238,7 @@ describe('Kernel.IKernel', () => { msgId: msgId, content: {} }); - msg2.parent_header = { session: kernel.clientId }; + msg2.parent_header = { session: kernel.clientId } as any; tester.send(msg2); await emission; @@ -303,7 +274,7 @@ describe('Kernel.IKernel', () => { msgId, content: {} }); - msg.parent_header = { session: kernel.clientId }; + msg.parent_header = { session: kernel.clientId } as any; tester.send(msg); await emission; }); @@ -393,7 +364,7 @@ describe('Kernel.IKernel', () => { find: () => defaultKernel.status === 'idle' }); await defaultKernel.requestExecute({ code: 'a=1' }).done; - await emission; + await expect(emission).resolves.not.toThrow(); }); it('should get a restarting status', async () => { @@ -404,17 +375,17 @@ describe('Kernel.IKernel', () => { }); await kernel.requestKernelInfo(); await kernel.restart(); - await emission; + await expect(emission).resolves.not.toThrow(); await kernel.requestKernelInfo(); await kernel.shutdown(); - }); + }, 30000); it('should get a busy status', async () => { const emission = testEmission(defaultKernel.statusChanged, { find: () => defaultKernel.status === 'busy' }); await defaultKernel.requestExecute({ code: 'a=1' }, true).done; - await emission; + await expect(emission).resolves.not.toThrow(); }); it('should get an unknown status while disconnected', async () => { @@ -425,7 +396,7 @@ describe('Kernel.IKernel', () => { }); await tester.close(); - await emission; + await expect(emission).resolves.not.toThrow(); tester.dispose(); }); @@ -437,7 +408,7 @@ describe('Kernel.IKernel', () => { find: () => kernel.status === 'dead' }); tester.sendStatus(UUID.uuid4(), 'dead'); - await dead; + await expect(dead).resolves.not.toThrow(); tester.dispose(); }); }); @@ -586,7 +557,7 @@ describe('Kernel.IKernel', () => { }); expect(() => { kernel.sendShellMessage(msg, true); - }).toThrowError(/Kernel is dead/); + }).toThrow(/Kernel is dead/); }); it('should handle out of order messages', async () => { @@ -632,14 +603,14 @@ describe('Kernel.IKernel', () => { ); }; }); - await future.done; + await expect(future.done).resolves.not.toThrow(); }); }); describe('#interrupt()', () => { it('should interrupt and resolve with a valid server response', async () => { const kernel = await kernelManager.startNew(); - await kernel.interrupt(); + await expect(kernel.interrupt()).resolves.not.toThrow(); await kernel.shutdown(); }); @@ -649,13 +620,13 @@ describe('Kernel.IKernel', () => { name: defaultKernel.name }); const interrupt = defaultKernel.interrupt(); - await expectFailure(interrupt, 'Invalid response: 200 OK'); + await expect(interrupt).rejects.toThrow(/Invalid response: 200 OK/); }); it('should throw an error for an error response', async () => { handleRequest(defaultKernel, 500, {}); const interrupt = defaultKernel.interrupt(); - await expectFailure(interrupt, ''); + await expect(interrupt).rejects.toThrow(); }); it('should fail if the kernel is dead', async () => { @@ -668,7 +639,7 @@ describe('Kernel.IKernel', () => { }); tester.sendStatus(UUID.uuid4(), 'dead'); await dead; - await expectFailure(kernel.interrupt(), 'Kernel is dead'); + await expect(kernel.interrupt()).rejects.toThrow(/Kernel is dead/); tester.dispose(); }); }); @@ -683,35 +654,34 @@ describe('Kernel.IKernel', () => { await kernel.info; await kernel.requestKernelInfo(); await kernel.restart(); - await kernel.requestKernelInfo(); + await expect(kernel.requestKernelInfo()).resolves.not.toThrow(); await kernel.shutdown(); }); it('should fail if the kernel does not restart', async () => { handleRequest(defaultKernel, 500, {}); const restart = defaultKernel.restart(); - await expectFailure(restart, ''); + await expect(restart).rejects.toThrow(); }); it('should throw an error for an invalid response', async () => { const { id, name } = defaultKernel; handleRequest(defaultKernel, 205, { id, name }); - await expectFailure( - defaultKernel.restart(), - 'Invalid response: 205 Reset Content' + await expect(defaultKernel.restart()).rejects.toThrow( + /Invalid response: 205 Reset Content/ ); }); it('should throw an error for an error response', async () => { handleRequest(defaultKernel, 500, {}); const restart = defaultKernel.restart(); - await expectFailure(restart); + await expect(restart).rejects.toThrow(); }); it('should throw an error for an invalid id', async () => { handleRequest(defaultKernel, 200, {}); const restart = defaultKernel.restart(); - await expectFailure(restart); + await expect(restart).rejects.toThrow(); }); it('should dispose of existing comm and future objects', async () => { @@ -745,26 +715,20 @@ describe('Kernel.IKernel', () => { } }); await defaultKernel.reconnect(); - await emission; + await expect(emission).resolves.not.toThrow(); }); it('return promise should reject if the kernel is disposed or disconnected', async () => { const connection = defaultKernel.reconnect(); defaultKernel.dispose(); - try { - await connection; - // If the connection did not reject, so test fails. - throw new Error('Reconnection promise did not reject'); - } catch (e) { - /* Connection promise reject - test passes */ - } + await expect(connection).rejects.toThrow(); }); }); describe('#shutdown()', () => { it('should shut down and resolve with a valid server response', async () => { const kernel = await kernelManager.startNew(); - await kernel.shutdown(); + await expect(kernel.shutdown()).resolves.not.toThrow(); }); it('should throw an error for an invalid response', async () => { @@ -773,19 +737,19 @@ describe('Kernel.IKernel', () => { name: 'foo' }); const shutdown = defaultKernel.shutdown(); - await expectFailure(shutdown, 'Invalid response: 200 OK'); + await expect(shutdown).rejects.toThrow(/Invalid response: 200 OK/); }); it('should handle a 404 error', async () => { const kernel = await kernelManager.startNew(); handleRequest(kernel, 404, {}); - await kernel.shutdown(); + await expect(kernel.shutdown()).resolves.not.toThrow(); }); it('should throw an error for an error response', async () => { handleRequest(defaultKernel, 500, {}); const shutdown = defaultKernel.shutdown(); - await expectFailure(shutdown, ''); + await expect(shutdown).rejects.toThrow(); }); it('should still pass if the kernel is dead', async () => { @@ -798,7 +762,7 @@ describe('Kernel.IKernel', () => { }); tester.sendStatus(UUID.uuid4(), 'dead'); await dead; - await kernel.shutdown(); + await expect(kernel.shutdown()).resolves.not.toThrow(); tester.dispose(); }); }); @@ -820,7 +784,9 @@ describe('Kernel.IKernel', () => { code: 'hello', cursor_pos: 4 }; - await defaultKernel.requestComplete(options); + await expect( + defaultKernel.requestComplete(options) + ).resolves.not.toThrow(); }); it('should reject the promise if the kernel is dead', async () => { @@ -837,7 +803,9 @@ describe('Kernel.IKernel', () => { }); tester.sendStatus(UUID.uuid4(), 'dead'); await dead; - await expectFailure(kernel.requestComplete(options), 'Kernel is dead'); + await expect(kernel.requestComplete(options)).rejects.toThrow( + /Kernel is dead/ + ); tester.dispose(); }); }); @@ -849,7 +817,9 @@ describe('Kernel.IKernel', () => { cursor_pos: 4, detail_level: 0 }; - await defaultKernel.requestInspect(options); + await expect( + defaultKernel.requestInspect(options) + ).resolves.not.toThrow(); }); }); @@ -858,7 +828,9 @@ describe('Kernel.IKernel', () => { const options: KernelMessage.IIsCompleteRequestMsg['content'] = { code: 'hello' }; - await defaultKernel.requestIsComplete(options); + await expect( + defaultKernel.requestIsComplete(options) + ).resolves.not.toThrow(); }); }); @@ -872,7 +844,9 @@ describe('Kernel.IKernel', () => { start: 1, stop: 2 }; - await defaultKernel.requestHistory(options); + await expect( + defaultKernel.requestHistory(options) + ).resolves.not.toThrow(); }); it('tail messages should resolve the promise', async () => { @@ -882,7 +856,9 @@ describe('Kernel.IKernel', () => { hist_access_type: 'tail', n: 1 }; - await defaultKernel.requestHistory(options); + await expect( + defaultKernel.requestHistory(options) + ).resolves.not.toThrow(); }); it('search messages should resolve the promise', async () => { @@ -894,7 +870,9 @@ describe('Kernel.IKernel', () => { pattern: '*', unique: true }; - await defaultKernel.requestHistory(options); + await expect( + defaultKernel.requestHistory(options) + ).resolves.not.toThrow(); }); }); @@ -945,7 +923,7 @@ describe('Kernel.IKernel', () => { version: '' } ); - }).toThrowError(/Kernel is dead/); + }).toThrow(/Kernel is dead/); tester.dispose(); }); }); @@ -983,7 +961,8 @@ describe('Kernel.IKernel', () => { status: 'ok', user_expressions: {} }, - parentHeader: msg.header as KernelMessage.IExecuteRequestMsg['header'] + parentHeader: + msg.header as KernelMessage.IExecuteRequestMsg['header'] }) ); diff --git a/packages/services/test/kernel/kernel.spec.ts b/packages/services/test/kernel/kernel.spec.ts index cd06cbfc3058..512d537be211 100644 --- a/packages/services/test/kernel/kernel.spec.ts +++ b/packages/services/test/kernel/kernel.spec.ts @@ -1,13 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { - expectFailure, - flakyIt as it, - JupyterServer, - testEmission -} from '@jupyterlab/testutils'; -import { toArray } from '@lumino/algorithm'; +import { JupyterServer, testEmission } from '@jupyterlab/testing'; import { UUID } from '@lumino/coreutils'; import { KernelAPI } from '../../src'; import { @@ -21,18 +15,20 @@ const PYTHON3_SPEC = JSON.parse(JSON.stringify(PYTHON_SPEC)); PYTHON3_SPEC.name = 'Python3'; PYTHON3_SPEC.display_name = 'python3'; -const server = new JupyterServer(); +describe('kernel', () => { + let tester: KernelTester; + let server: JupyterServer; -beforeAll(async () => { - await server.start(); -}); + jest.retryTimes(3); -afterAll(async () => { - await server.shutdown(); -}); + beforeAll(async () => { + server = new JupyterServer(); + await server.start(); + }, 30000); -describe('kernel', () => { - let tester: KernelTester; + afterAll(async () => { + await server.shutdown(); + }); afterEach(async () => { if (tester) { @@ -45,7 +41,9 @@ describe('kernel', () => { describe('Kernel.listRunning()', () => { it('should yield a list of valid kernel ids', async () => { const kernel = await KernelAPI.startNew(); - expect(toArray(await KernelAPI.listRunning()).length).toBeGreaterThan(0); + expect(Array.from(await KernelAPI.listRunning()).length).toBeGreaterThan( + 0 + ); await KernelAPI.shutdownKernel(kernel.id); }); @@ -53,7 +51,7 @@ describe('kernel', () => { const serverSettings = makeSettings(); const k = await KernelAPI.startNew({}, serverSettings); const response = await KernelAPI.listRunning(serverSettings); - expect(toArray(response).length).toBeGreaterThan(0); + expect(Array.from(response).length).toBeGreaterThan(0); await KernelAPI.shutdownKernel(k.id); }); @@ -61,19 +59,19 @@ describe('kernel', () => { const data = { id: UUID.uuid4(), name: 'test' }; const settings = getRequestHandler(200, data); const promise = KernelAPI.listRunning(settings); - await expectFailure(promise, 'Invalid kernel list'); + await expect(promise).rejects.toThrow(/Invalid kernel list/); }); it('should throw an error for an invalid response', async () => { const settings = getRequestHandler(201, {}); const promise = KernelAPI.listRunning(settings); - await expectFailure(promise, 'Invalid response: 201 Created'); + await expect(promise).rejects.toThrow(/Invalid response: 201 Created/); }); it('should throw an error for an error response', async () => { const settings = getRequestHandler(500, {}); const promise = KernelAPI.listRunning(settings); - await expectFailure(promise, ''); + await expect(promise).rejects.toThrow(); }); }); @@ -81,7 +79,7 @@ describe('kernel', () => { it('should accept ajax options', async () => { const serverSettings = makeSettings(); const k = await KernelAPI.startNew({}, serverSettings); - await KernelAPI.shutdownKernel(k.id); + await expect(KernelAPI.shutdownKernel(k.id)).resolves.not.toThrow(); }); it('should still construct connection if the kernel dies', async () => { @@ -102,7 +100,7 @@ describe('kernel', () => { it('should throw an error for an invalid kernel id', async () => { const serverSettings = getRequestHandler(201, { id: UUID.uuid4() }); const kernelPromise = KernelAPI.startNew({}, serverSettings); - await expectFailure(kernelPromise); + await expect(kernelPromise).rejects.toThrow(); }); it('should throw an error for another invalid kernel id', async () => { @@ -111,20 +109,20 @@ describe('kernel', () => { name: 1 }); const kernelPromise = KernelAPI.startNew({}, serverSettings); - await expectFailure(kernelPromise); + await expect(kernelPromise).rejects.toThrow(); }); it('should throw an error for an invalid response', async () => { const data = { id: UUID.uuid4(), name: 'foo' }; const serverSettings = getRequestHandler(200, data); const kernelPromise = KernelAPI.startNew({}, serverSettings); - await expectFailure(kernelPromise, 'Invalid response: 200 OK'); + await expect(kernelPromise).rejects.toThrow(/Invalid response: 200 OK/); }); it('should throw an error for an error response', async () => { const serverSettings = getRequestHandler(500, {}); const kernelPromise = KernelAPI.startNew({}, serverSettings); - await expectFailure(kernelPromise, ''); + await expect(kernelPromise).rejects.toThrow(); }); it('should auto-reconnect on websocket error', async () => { @@ -136,7 +134,7 @@ describe('kernel', () => { find: (k, status) => status === 'connecting' }); await tester.close(); - await emission; + await expect(emission).resolves.not.toThrow(); }); }); @@ -148,8 +146,10 @@ describe('kernel', () => { expect(kernels.find(k => k.id === kernel.id)).toBeUndefined(); }); - it('should handle a 404 error', () => { - return KernelAPI.shutdownKernel(UUID.uuid4()); + it('should handle a 404 error', async () => { + await expect( + KernelAPI.shutdownKernel(UUID.uuid4()) + ).resolves.not.toThrow(); }); }); }); diff --git a/packages/services/test/kernel/manager.spec.ts b/packages/services/test/kernel/manager.spec.ts index 271a822a9419..29256de57941 100644 --- a/packages/services/test/kernel/manager.spec.ts +++ b/packages/services/test/kernel/manager.spec.ts @@ -1,50 +1,43 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { - flakyIt as it, - JupyterServer, - sleep, - testEmission -} from '@jupyterlab/testutils'; -import { toArray } from '@lumino/algorithm'; +import { JupyterServer, sleep, testEmission } from '@jupyterlab/testing'; import { Kernel, KernelAPI, KernelManager } from '../../src'; import { makeSettings } from '../utils'; -const server = new JupyterServer(); - -beforeAll(async () => { - await server.start(); -}); - -afterAll(async () => { - await server.shutdown(); -}); - describe('kernel/manager', () => { - let manager: KernelManager; let kernel: Kernel.IModel; + let server: JupyterServer; + + jest.retryTimes(3); beforeAll(async () => { - jest.setTimeout(20000); + server = new JupyterServer(); + await server.start(); kernel = await KernelAPI.startNew(); - }); - - beforeEach(() => { - manager = new KernelManager({ standby: 'never' }); - return manager.ready; - }); - - afterEach(() => { - manager.dispose(); - }); + }, 30000); afterAll(async () => { - const models = await KernelAPI.listRunning(); - await Promise.all(models.map(m => KernelAPI.shutdownKernel(m.id))); + await server.shutdown(); }); describe('KernelManager', () => { + let manager: KernelManager; + + beforeEach(() => { + manager = new KernelManager({ standby: 'never' }); + return manager.ready; + }); + + afterEach(() => { + manager.dispose(); + }); + + afterAll(async () => { + const models = await KernelAPI.listRunning(); + await Promise.all(models.map(m => KernelAPI.shutdownKernel(m.id))); + }); + describe('#constructor()', () => { it('should take the options as an argument', async () => { manager.dispose(); @@ -72,7 +65,7 @@ describe('kernel/manager', () => { describe('#running()', () => { it('should get the running sessions', async () => { await manager.refreshRunning(); - expect(toArray(manager.running()).length).toBeGreaterThan(0); + expect(Array.from(manager.running()).length).toBeGreaterThan(0); }); }); describe('#runningChanged', () => { @@ -80,7 +73,7 @@ describe('kernel/manager', () => { let called = false; manager.runningChanged.connect((sender, args) => { expect(sender).toBe(manager); - expect(toArray(args).length).toBeGreaterThan(0); + expect(Array.from(args).length).toBeGreaterThan(0); called = true; }); await KernelAPI.startNew(); @@ -112,28 +105,28 @@ describe('kernel/manager', () => { }); describe('#ready', () => { - it('should resolve when the manager is ready', () => { - return manager.ready; + it('should resolve when the manager is ready', async () => { + await expect(manager.ready).resolves.not.toThrow(); }); }); describe('#refreshRunning()', () => { it('should update the running kernels', async () => { await manager.refreshRunning(); - expect(toArray(manager.running()).length).toBeGreaterThan(0); + expect(Array.from(manager.running()).length).toBeGreaterThan(0); }); it('should update the running kernels when one is shut down', async () => { - const old = toArray(manager.running()).length; + const old = Array.from(manager.running()).length; await KernelAPI.startNew(); await manager.refreshRunning(); - expect(toArray(manager.running()).length).toBeGreaterThan(old); + expect(Array.from(manager.running()).length).toBeGreaterThan(old); }); }); describe('#startNew()', () => { - it('should start a new kernel', () => { - return manager.startNew(); + it('should start a new kernel', async () => { + await expect(manager.startNew()).resolves.not.toThrow(); }); it('should emit a runningChanged signal', async () => { @@ -200,4 +193,75 @@ describe('kernel/manager', () => { }); }); }); + + describe('NoopManager', () => { + let manager: KernelManager.NoopManager; + + beforeEach(async () => { + manager = new KernelManager.NoopManager({ standby: 'never' }); + await manager.parentReady; + }); + + afterEach(() => { + manager.dispose(); + }); + + describe('#constructor()', () => { + it('should take the options as an argument', async () => { + manager.dispose(); + manager = new KernelManager.NoopManager({ + serverSettings: makeSettings(), + standby: 'never' + }); + await manager.parentReady; + expect(manager instanceof KernelManager.NoopManager).toBe(true); + }); + }); + + describe('#serverSettings', () => { + it('should get the server settings', async () => { + manager.dispose(); + const serverSettings = makeSettings(); + const standby = 'never'; + const token = serverSettings.token; + manager = new KernelManager.NoopManager({ serverSettings, standby }); + await manager.parentReady; + expect(manager.serverSettings.token).toBe(token); + }); + }); + + describe('#running()', () => { + it('should get the running sessions', async () => { + await manager.refreshRunning(); + expect(Array.from(manager.running()).length).toEqual(0); + }); + }); + + describe('#refreshRunning()', () => { + it('should update the running kernels', async () => { + await manager.refreshRunning(); + expect(Array.from(manager.running()).length).toEqual(0); + }); + }); + + describe('#startNew()', () => { + it('should throw an error', () => { + return expect(manager.startNew()).rejects.toThrow(); + }); + }); + + describe('#connectTo()', () => { + it('should throw an error', () => { + return expect(() => { + manager.connectTo({ model: kernel }); + }).toThrow(); + }); + }); + + describe('shutdown()', () => { + it('should throw an error', () => { + return expect(manager.shutdown(kernel.id)).rejects.toThrow(); + }); + }); + }); }); diff --git a/packages/services/test/kernel/validate.spec.ts b/packages/services/test/kernel/validate.spec.ts index 57786336b518..0545a80e5a08 100644 --- a/packages/services/test/kernel/validate.spec.ts +++ b/packages/services/test/kernel/validate.spec.ts @@ -13,7 +13,9 @@ describe('kernel/validate', () => { session: 'foo', content: { comm_id: 'foo', data: {} } }); - validateMessage(msg); + expect(() => { + validateMessage(msg); + }).not.toThrow(); }); it('should throw if missing a field', () => { @@ -24,7 +26,7 @@ describe('kernel/validate', () => { content: { comm_id: 'foo', data: {} } }); delete (msg as any).channel; - expect(() => validateMessage(msg)).toThrowError(); + expect(() => validateMessage(msg)).toThrow(); }); it('should throw if a field is invalid', () => { @@ -35,7 +37,7 @@ describe('kernel/validate', () => { content: { comm_id: 'foo', data: {} } }); (msg as any).header.username = 1; - expect(() => validateMessage(msg)).toThrowError(); + expect(() => validateMessage(msg)).toThrow(); }); it('should throw if the parent header is given an invalid', () => { @@ -47,7 +49,7 @@ describe('kernel/validate', () => { }); msg.parent_header = msg.header; (msg as any).parent_header.username = 1; - expect(() => validateMessage(msg)).toThrowError(); + expect(() => validateMessage(msg)).toThrow(); }); it('should throw if the channel is not a string', () => { @@ -58,7 +60,7 @@ describe('kernel/validate', () => { content: { comm_id: 'foo', data: {} } }); (msg as any).channel = 1; - expect(() => validateMessage(msg)).toThrowError(); + expect(() => validateMessage(msg)).toThrow(); }); it('should validate an iopub message', () => { @@ -68,7 +70,9 @@ describe('kernel/validate', () => { session: 'baz', content: { comm_id: 'foo', data: {} } }); - validateMessage(msg); + expect(() => { + validateMessage(msg); + }).not.toThrow(); }); it('should ignore on an unknown iopub message type', () => { @@ -78,7 +82,9 @@ describe('kernel/validate', () => { session: 'baz', content: {} } as any); - validateMessage(msg); + expect(() => { + validateMessage(msg); + }).not.toThrow(); }); it('should throw on missing iopub message content', () => { @@ -88,7 +94,7 @@ describe('kernel/validate', () => { session: 'baz', content: {} as any } as any); - expect(() => validateMessage(msg)).toThrowError(); + expect(() => validateMessage(msg)).toThrow(); }); it('should throw on invalid iopub message content', () => { @@ -98,7 +104,7 @@ describe('kernel/validate', () => { session: 'baz', content: { wait: 1 as any } }); - expect(() => validateMessage(msg)).toThrowError(); + expect(() => validateMessage(msg)).toThrow(); }); it('should throw on invalid iopub status message content', () => { @@ -108,7 +114,7 @@ describe('kernel/validate', () => { session: 'baz', content: { execution_state: 'invalid-status' as Kernel.Status } }); - expect(() => validateMessage(msg)).toThrowError(); + expect(() => validateMessage(msg)).toThrow(); }); it('should handle no buffers field', () => { @@ -119,14 +125,18 @@ describe('kernel/validate', () => { content: { comm_id: 'foo', data: {} } }); delete msg['buffers']; - validateMessage(msg); + expect(() => { + validateMessage(msg); + }).not.toThrow(); }); }); describe('#validateModel()', () => { it('should pass a valid id', () => { const id: Kernel.IModel = { name: 'foo', id: 'baz' }; - validateModel(id); + expect(() => { + validateModel(id); + }).not.toThrow(); }); }); }); diff --git a/packages/services/test/kernelspec/kernelspec.spec.ts b/packages/services/test/kernelspec/kernelspec.spec.ts index 6ba7fff0e21d..e52a2b8795ea 100644 --- a/packages/services/test/kernelspec/kernelspec.spec.ts +++ b/packages/services/test/kernelspec/kernelspec.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { expectFailure, JupyterServer } from '@jupyterlab/testutils'; +import { JupyterServer } from '@jupyterlab/testing'; import { KernelSpecAPI } from '../../src'; import { getRequestHandler, makeSettings, PYTHON_SPEC } from '../utils'; @@ -13,7 +13,7 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); @@ -45,7 +45,7 @@ describe('kernel', () => { default: PYTHON_SPEC.name }); const promise = KernelSpecAPI.getSpecs(serverSettings); - await expectFailure(promise, 'No kernelspecs found'); + await expect(promise).rejects.toThrow(/No kernelspecs found/); }); it('should omit an invalid kernelspec', async () => { @@ -71,7 +71,7 @@ describe('kernel', () => { kernelspecs: { R: R_SPEC } }); const promise = KernelSpecAPI.getSpecs(serverSettings); - await expectFailure(promise, 'No valid kernelspecs found'); + await expect(promise).rejects.toThrow(/No valid kernelspecs found/); }); it('should handle an improper language', async () => { @@ -82,7 +82,7 @@ describe('kernel', () => { kernelspecs: { R: R_SPEC } }); const promise = KernelSpecAPI.getSpecs(serverSettings); - await expectFailure(promise, 'No valid kernelspecs found'); + await expect(promise).rejects.toThrow(/No valid kernelspecs found/); }); it('should handle an improper argv', async () => { @@ -93,7 +93,7 @@ describe('kernel', () => { kernelspecs: { R: R_SPEC } }); const promise = KernelSpecAPI.getSpecs(serverSettings); - await expectFailure(promise, 'No valid kernelspecs found'); + await expect(promise).rejects.toThrow(/No valid kernelspecs found/); }); it('should handle an improper display_name', async () => { @@ -104,7 +104,7 @@ describe('kernel', () => { kernelspecs: { R: R_SPEC } }); const promise = KernelSpecAPI.getSpecs(serverSettings); - await expectFailure(promise, 'No valid kernelspecs found'); + await expect(promise).rejects.toThrow(/No valid kernelspecs found/); }); it('should handle missing resources', async () => { @@ -115,17 +115,18 @@ describe('kernel', () => { kernelspecs: { R: R_SPEC } }); const promise = KernelSpecAPI.getSpecs(serverSettings); - await expectFailure(promise, 'No valid kernelspecs found'); + await expect(promise).rejects.toThrow(/No valid kernelspecs found/); }); it('should throw an error for an invalid response', async () => { const serverSettings = getRequestHandler(201, {}); const promise = KernelSpecAPI.getSpecs(serverSettings); - await expectFailure(promise, 'Invalid response: 201 Created'); + await expect(promise).rejects.toThrow(/Invalid response: 201 Created/); }); it('should handle metadata', async () => { const PYTHON_SPEC_W_MD = JSON.parse(JSON.stringify(PYTHON_SPEC)); + // eslint-disable-next-line camelcase PYTHON_SPEC_W_MD.spec.metadata = { some_application: { key: 'value' } }; const serverSettings = getRequestHandler(200, { default: 'python', diff --git a/packages/services/test/kernelspec/manager.spec.ts b/packages/services/test/kernelspec/manager.spec.ts index b60c5cd55548..8d9d8320138b 100644 --- a/packages/services/test/kernelspec/manager.spec.ts +++ b/packages/services/test/kernelspec/manager.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { JupyterServer } from '@jupyterlab/testutils'; +import { JupyterServer } from '@jupyterlab/testing'; import { JSONExt } from '@lumino/coreutils'; import { KernelSpec, KernelSpecManager } from '../../src'; import { @@ -29,7 +29,7 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); @@ -106,8 +106,8 @@ describe('kernel/manager', () => { }); describe('#ready', () => { - it('should resolve when the manager is ready', () => { - return manager.ready; + it('should resolve when the manager is ready', async () => { + await expect(manager.ready).resolves.not.toThrow(); }); }); diff --git a/packages/services/test/kernelspec/validate.spec.ts b/packages/services/test/kernelspec/validate.spec.ts index aae22d031e13..293d109135f8 100644 --- a/packages/services/test/kernelspec/validate.spec.ts +++ b/packages/services/test/kernelspec/validate.spec.ts @@ -11,19 +11,21 @@ import { PYTHON_SPEC } from '../utils'; describe('kernelspec/validate', () => { describe('#validateSpecModel', () => { it('should pass with valid data', () => { - validateSpecModel(PYTHON_SPEC); + expect(() => { + validateSpecModel(PYTHON_SPEC); + }).not.toThrow(); }); it('should fail on missing data', () => { const spec = JSON.parse(JSON.stringify(PYTHON_SPEC)); delete spec['name']; - expect(() => validateSpecModel(spec)).toThrowError(); + expect(() => validateSpecModel(spec)).toThrow(); }); it('should fail on incorrect data', () => { const spec = JSON.parse(JSON.stringify(PYTHON_SPEC)); spec.spec.language = 1; - expect(() => validateSpecModel(spec)).toThrowError(); + expect(() => validateSpecModel(spec)).toThrow(); }); }); @@ -35,14 +37,16 @@ describe('kernelspec/validate', () => { python: PYTHON_SPEC } }; - validateSpecModels(model); + expect(() => { + validateSpecModels(model); + }).not.toThrow(); }); it('should fail on missing data', () => { const model: any = { default: 'python' }; - expect(() => validateSpecModels(model)).toThrowError(); + expect(() => validateSpecModels(model)).toThrow(); }); }); }); diff --git a/packages/services/test/manager.spec.ts b/packages/services/test/manager.spec.ts index 0659a9a29693..f1be5f5de031 100644 --- a/packages/services/test/manager.spec.ts +++ b/packages/services/test/manager.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { JupyterServer } from '@jupyterlab/testutils'; +import { JupyterServer } from '@jupyterlab/testing'; import { ContentsManager, ServiceManager, @@ -15,7 +15,7 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); diff --git a/testutils/test/mock.spec.ts b/packages/services/test/mock.spec.ts similarity index 76% rename from testutils/test/mock.spec.ts rename to packages/services/test/mock.spec.ts index 681c8e6fc462..c9885f2efb72 100644 --- a/testutils/test/mock.spec.ts +++ b/packages/services/test/mock.spec.ts @@ -1,70 +1,10 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import * as Mock from '../src/mock'; +import * as Mock from '@jupyterlab/services/lib/testutils'; import { KernelMessage } from '@jupyterlab/services'; -import { toArray } from '@lumino/algorithm'; describe('mock', () => { - describe('createSimpleSessionContext()', () => { - it('should create a session context', () => { - const context = Mock.createSimpleSessionContext(); - expect(context.session!.kernel!.name).toEqual(Mock.DEFAULT_NAME); - }); - - it('should accept a session model', () => { - const context = Mock.createSimpleSessionContext({ - name: 'hi', - path: 'foo', - type: 'bar', - kernel: { name: 'fizz' } - }); - expect(context.name).toEqual('hi'); - expect(context.path).toEqual('foo'); - expect(context.type).toEqual('bar'); - expect(context.session!.kernel!.name).toEqual('fizz'); - }); - }); - - describe('updateKernelStatus()', () => { - it('should update the kernel status', () => { - const context = Mock.createSimpleSessionContext(); - let called = false; - context.statusChanged.connect((_, status) => { - if (status === 'dead') { - called = true; - } - }); - Mock.updateKernelStatus(context, 'dead'); - expect(context.session!.kernel!.status).toEqual('dead'); - expect(called).toEqual(true); - }); - }); - - describe('emitIopubMessage', () => { - it('should emit an iopub message', () => { - const context = Mock.createSimpleSessionContext(); - const source = KernelMessage.createMessage({ - channel: 'iopub', - msgType: 'execute_input', - session: 'foo', - username: 'bar', - msgId: 'fizz', - content: { - code: 'hello, world!', - execution_count: 0 - } - }); - let called = false; - context.iopubMessage.connect((_, msg) => { - expect(msg).toBe(source); - called = true; - }); - Mock.emitIopubMessage(context, source); - expect(called).toBe(true); - }); - }); - describe('cloneKernel()', () => { it('should clone a kernel', () => { const kernel0 = new Mock.KernelMock({}); @@ -98,7 +38,9 @@ describe('mock', () => { describe('.dispose()', () => { it('should be a no-op', () => { const kernel = new Mock.KernelMock({}); - kernel.dispose(); + expect(() => { + kernel.dispose(); + }).not.toThrow(); }); }); @@ -122,7 +64,7 @@ describe('mock', () => { describe('.shutdown()', () => { it('should be a no-op', async () => { const kernel = new Mock.KernelMock({}); - await kernel.shutdown(); + await expect(kernel.shutdown()).resolves.not.toThrow(); }); }); @@ -137,7 +79,7 @@ describe('mock', () => { describe('.restart()', () => { it('should be a no-op', async () => { const kernel = new Mock.KernelMock({}); - await kernel.restart(); + await expect(kernel.restart()).resolves.not.toThrow(); }); }); @@ -178,7 +120,9 @@ describe('mock', () => { describe('.dispose()', () => { it('should be a no-op', () => { const session = new Mock.SessionConnectionMock({}, null); - session.dispose(); + expect(() => { + session.dispose(); + }).not.toThrow(); }); }); @@ -194,7 +138,7 @@ describe('mock', () => { describe('.shutdown()', () => { it('should be a no-op', async () => { const session = new Mock.SessionConnectionMock({}, null); - await session.shutdown(); + await expect(session.shutdown()).resolves.not.toThrow(); }); }); @@ -244,59 +188,6 @@ describe('mock', () => { }); }); - describe('SessionContextMock', () => { - describe('.constructor()', () => { - it('should create a new context', () => { - const context = new Mock.SessionContextMock({}, null); - expect(context.session!.kernel!.name).toBe(Mock.DEFAULT_NAME); - }); - - it('should accept options', () => { - const session = new Mock.SessionConnectionMock({}, null); - const context = new Mock.SessionContextMock({ path: 'foo' }, session); - expect(context.session).toBe(session); - expect(context.path).toBe('foo'); - }); - }); - - describe('.dispose()', () => { - it('should be a no-op', () => { - const context = new Mock.SessionContextMock({}, null); - context.dispose(); - }); - }); - - describe('.initialize()', () => { - it('should be a no-op', async () => { - const context = new Mock.SessionContextMock({}, null); - await context.initialize(); - }); - }); - - describe('.ready', () => { - it('should be a no-op', async () => { - const context = new Mock.SessionContextMock({}, null); - await context.ready; - }); - }); - - describe('.changeKernel()', () => { - it('should change the kernel', async () => { - const context = new Mock.SessionContextMock({}, null); - const oldId = context.session!.kernel!.id; - const kernel = await context.changeKernel({ name: Mock.DEFAULT_NAME }); - expect(kernel!.id).not.toBe(oldId); - }); - }); - - describe('.shutdown()', () => { - it('should be a no-op', async () => { - const context = new Mock.SessionContextMock({}, null); - await context.shutdown(); - }); - }); - }); - describe('ContentsManagerMock', () => { describe('.constructor()', () => { it('should create a new mock', () => { @@ -369,13 +260,6 @@ describe('mock', () => { }); }); - describe('.getModelDBFactory()', () => { - it('should return null', () => { - const manager = new Mock.ContentsManagerMock(); - expect(manager.getModelDBFactory('foo')).toBe(null); - }); - }); - describe('.normalize()', () => { it('should normalize a path', () => { const manager = new Mock.ContentsManagerMock(); @@ -463,7 +347,9 @@ describe('mock', () => { describe('.dispose()', () => { it('should be a no-op', () => { const manager = new Mock.ContentsManagerMock(); - manager.dispose(); + expect(() => { + manager.dispose(); + }).not.toThrow(); }); }); }); @@ -514,16 +400,16 @@ describe('mock', () => { type: 'bar', kernel: { name: Mock.DEFAULT_NAME } }); - expect(toArray(manager.running()).length).toBe(1); + expect(Array.from(manager.running()).length).toBe(1); await manager.stopIfNeeded(session.path); - expect(toArray(manager.running()).length).toBe(0); + expect(Array.from(manager.running()).length).toBe(0); }); }); describe('.refreshRunning()', () => { it('should be a no-op', async () => { const manager = new Mock.SessionManagerMock(); - await manager.refreshRunning(); + await expect(manager.refreshRunning()).resolves.not.toThrow(); }); }); @@ -536,7 +422,7 @@ describe('mock', () => { type: 'bar', kernel: { name: Mock.DEFAULT_NAME } }); - expect(toArray(manager.running()).length).toBe(1); + expect(Array.from(manager.running()).length).toBe(1); }); }); }); @@ -559,7 +445,7 @@ describe('mock', () => { describe('.refreshSpecs()', () => { it('should be a no-op', async () => { const manager = new Mock.KernelSpecManagerMock(); - await manager.refreshSpecs(); + await expect(manager.refreshSpecs()).resolves.not.toThrow(); }); }); }); @@ -575,7 +461,7 @@ describe('mock', () => { describe('.ready', () => { it('should resolve', async () => { const manager = new Mock.ServiceManagerMock(); - await manager.ready; + await expect(manager.ready).resolves.not.toThrow(); }); }); @@ -603,7 +489,9 @@ describe('mock', () => { describe('.dispose()', () => { it('should be a no-op', () => { const manager = new Mock.ServiceManagerMock(); - manager.dispose(); + expect(() => { + manager.dispose(); + }).not.toThrow(); }); }); }); @@ -628,18 +516,4 @@ describe('mock', () => { future.dispose(); }); }); - - describe('createFileContext()', () => { - it('should create a context without a kernel', async () => { - const context = await Mock.createFileContext(); - expect(context.sessionContext.session).toBe(null); - }); - - it('should create a context with a kernel', async () => { - const context = await Mock.createFileContext(true); - expect(context.sessionContext.session!.kernel!.name).toBe( - Mock.DEFAULT_NAME - ); - }); - }); }); diff --git a/packages/services/test/serverconnection.spec.ts b/packages/services/test/serverconnection.spec.ts index c44205a06f15..39a8626e7c04 100644 --- a/packages/services/test/serverconnection.spec.ts +++ b/packages/services/test/serverconnection.spec.ts @@ -2,7 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { PageConfig } from '@jupyterlab/coreutils'; -import { JupyterServer } from '@jupyterlab/testutils'; +import { JupyterServer } from '@jupyterlab/testing'; import { ServerConnection } from '../src'; import { getRequestHandler } from './utils'; @@ -10,7 +10,7 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); diff --git a/packages/services/test/session/isession.spec.ts b/packages/services/test/session/isession.spec.ts index 3f69ac52c018..f5d786b8d575 100644 --- a/packages/services/test/session/isession.spec.ts +++ b/packages/services/test/session/isession.spec.ts @@ -2,12 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { PageConfig } from '@jupyterlab/coreutils'; -import { - expectFailure, - flakyIt as it, - JupyterServer, - testEmission -} from '@jupyterlab/testutils'; +import { JupyterServer, sleep, testEmission } from '@jupyterlab/testing'; import { UUID } from '@lumino/coreutils'; import { Signal } from '@lumino/signaling'; import { @@ -34,26 +29,20 @@ async function startNew(): Promise { return session; } -const server = new JupyterServer(); - -beforeAll(async () => { - await server.start(); - kernelManager = new KernelManager(); - sessionManager = new SessionManager({ kernelManager }); -}); - -afterAll(async () => { - await server.shutdown(); -}); - describe('session', () => { let session: Session.ISessionConnection; let defaultSession: Session.ISessionConnection; + let server: JupyterServer; + + jest.retryTimes(3); beforeAll(async () => { - jest.setTimeout(20000); + server = new JupyterServer(); + await server.start(); + kernelManager = new KernelManager(); + sessionManager = new SessionManager({ kernelManager }); defaultSession = await startNew(); - }); + }, 30000); afterEach(async () => { if (session && !session.isDisposed) { @@ -63,6 +52,7 @@ describe('session', () => { afterAll(async () => { await defaultSession.shutdown(); + await server.shutdown(); }); describe('Session.DefaultSession', () => { @@ -83,7 +73,10 @@ describe('session', () => { it('should emit when the kernel changes', async () => { let called: Session.ISessionConnection.IKernelChangedArgs | null = null; const object = {}; - await defaultSession.kernel?.requestKernelInfo(); + while (defaultSession.kernel!.connectionStatus !== 'connected') { + await sleep(100); + } + await defaultSession.kernel!.requestKernelInfo(); defaultSession.kernelChanged.connect((s, args) => { called = args; Signal.disconnectReceiver(object); @@ -109,6 +102,9 @@ describe('session', () => { called = true; } }); + while (defaultSession.kernel!.connectionStatus !== 'connected') { + await sleep(100); + } await defaultSession.kernel!.requestKernelInfo(); expect(called).toBe(true); }); @@ -128,8 +124,17 @@ describe('session', () => { }); describe('#unhandledMessage', () => { + let tester: SessionTester; + + beforeEach(() => { + tester = new SessionTester(); + }); + + afterEach(() => { + tester.dispose(); + }); + it('should be emitted for an unhandled message', async () => { - const tester = new SessionTester(); const session = await tester.startSession(); const msgId = UUID.uuid4(); const emission = testEmission(session.unhandledMessage, { @@ -142,11 +147,10 @@ describe('session', () => { msgId, content: {} }); - msg.parent_header = { session: session.kernel!.clientId }; + msg.parent_header = { session: session.kernel!.clientId } as any; tester.send(msg); await emission; - await tester.shutdown(); - tester.dispose(); + await expect(tester.shutdown()).resolves.not.toThrow(); }); }); @@ -264,17 +268,17 @@ describe('session', () => { it('should fail for improper response status', async () => { handleRequest(defaultSession, 201, {}); - await expectFailure(defaultSession.setPath(UUID.uuid4())); + await expect(defaultSession.setPath(UUID.uuid4())).rejects.toThrow(); }); it('should fail for error response status', async () => { handleRequest(defaultSession, 500, {}); - await expectFailure(defaultSession.setPath(UUID.uuid4()), ''); + await expect(defaultSession.setPath(UUID.uuid4())).rejects.toThrow(); }); it('should fail for improper model', async () => { handleRequest(defaultSession, 200, {}); - await expectFailure(defaultSession.setPath(UUID.uuid4())); + await expect(defaultSession.setPath(UUID.uuid4())).rejects.toThrow(); }); it('should fail if the session is disposed', async () => { @@ -283,7 +287,7 @@ describe('session', () => { }); session.dispose(); const promise = session.setPath(UUID.uuid4()); - await expectFailure(promise, 'Session is disposed'); + await expect(promise).rejects.toThrow(/Session is disposed/); }); }); @@ -298,17 +302,17 @@ describe('session', () => { it('should fail for improper response status', async () => { handleRequest(defaultSession, 201, {}); - await expectFailure(defaultSession.setType(UUID.uuid4())); + await expect(defaultSession.setType(UUID.uuid4())).rejects.toThrow(); }); it('should fail for error response status', async () => { handleRequest(defaultSession, 500, {}); - await expectFailure(defaultSession.setType(UUID.uuid4()), ''); + await expect(defaultSession.setType(UUID.uuid4())).rejects.toThrow(); }); it('should fail for improper model', async () => { handleRequest(defaultSession, 200, {}); - await expectFailure(defaultSession.setType(UUID.uuid4())); + await expect(defaultSession.setType(UUID.uuid4())).rejects.toThrow(); }); it('should fail if the session is disposed', async () => { @@ -317,7 +321,7 @@ describe('session', () => { }); session.dispose(); const promise = session.setPath(UUID.uuid4()); - await expectFailure(promise, 'Session is disposed'); + await expect(promise).rejects.toThrow(/Session is disposed/); }); }); @@ -330,17 +334,17 @@ describe('session', () => { it('should fail for improper response status', async () => { handleRequest(defaultSession, 201, {}); - await expectFailure(defaultSession.setName(UUID.uuid4())); + await expect(defaultSession.setName(UUID.uuid4())).rejects.toThrow(); }); it('should fail for error response status', async () => { handleRequest(defaultSession, 500, {}); - await expectFailure(defaultSession.setName(UUID.uuid4()), ''); + await expect(defaultSession.setName(UUID.uuid4())).rejects.toThrow(); }); it('should fail for improper model', async () => { handleRequest(defaultSession, 200, {}); - await expectFailure(defaultSession.setName(UUID.uuid4())); + await expect(defaultSession.setName(UUID.uuid4())).rejects.toThrow(); }); it('should fail if the session is disposed', async () => { @@ -349,7 +353,7 @@ describe('session', () => { }); session.dispose(); const promise = session.setPath(UUID.uuid4()); - await expectFailure(promise, 'Session is disposed'); + await expect(promise).rejects.toThrow(/Session is disposed/); }); }); @@ -394,7 +398,7 @@ describe('session', () => { describe('#shutdown()', () => { it('should shut down properly', async () => { session = await startNew(); - await session.shutdown(); + await expect(session.shutdown()).resolves.not.toThrow(); }); it('should emit a disposed signal', async () => { @@ -409,13 +413,13 @@ describe('session', () => { it('should fail for an incorrect response status', async () => { handleRequest(defaultSession, 200, {}); - await expectFailure(defaultSession.shutdown()); + await expect(defaultSession.shutdown()).rejects.toThrow(); }); it('should handle a 404 status', async () => { session = await startNew(); handleRequest(session, 404, {}); - await session.shutdown(); + await expect(session.shutdown()).resolves.not.toThrow(); }); it('should handle a specific error status', async () => { @@ -428,7 +432,7 @@ describe('session', () => { it('should fail for an error response status', async () => { handleRequest(defaultSession, 500, {}); - await expectFailure(defaultSession.shutdown(), ''); + await expect(defaultSession.shutdown()).rejects.toThrow(); }); it('should fail if the session is disposed', async () => { @@ -436,7 +440,7 @@ describe('session', () => { model: defaultSession.model }); session.dispose(); - await expectFailure(session.shutdown(), 'Session is disposed'); + await expect(session.shutdown()).rejects.toThrow(/Session is disposed/); }); }); }); diff --git a/packages/services/test/session/manager.spec.ts b/packages/services/test/session/manager.spec.ts index 07f958ebadfe..6add86dcaa55 100644 --- a/packages/services/test/session/manager.spec.ts +++ b/packages/services/test/session/manager.spec.ts @@ -1,12 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { - flakyIt as it, - JupyterServer, - testEmission -} from '@jupyterlab/testutils'; -import { toArray } from '@lumino/algorithm'; +import { JupyterServer, testEmission } from '@jupyterlab/testing'; import { UUID } from '@lumino/coreutils'; import { KernelManager, @@ -30,43 +25,39 @@ async function startNew( return session; } -const server = new JupyterServer(); - -beforeAll(async () => { - await server.start(); -}); - -afterAll(async () => { - await server.shutdown(); -}); - describe('session/manager', () => { - let kernelManager: KernelManager; - let manager: SessionManager; - let session: Session.ISessionConnection; - - beforeAll(() => { - jest.setTimeout(20000); - kernelManager = new KernelManager({ standby: 'never' }); - }); + let server: JupyterServer; + jest.setTimeout(20000); + jest.retryTimes(3); - beforeEach(async () => { - manager = new SessionManager({ kernelManager, standby: 'never' }); - await manager.ready; - session = await startNew(manager); - await session.kernel!.info; - }); - - afterEach(() => { - manager.dispose(); - }); + beforeAll(async () => { + server = new JupyterServer(); + await server.start(); + }, 30000); afterAll(async () => { const sessions = await SessionAPI.listRunning(); await Promise.all(sessions.map(s => SessionAPI.shutdownSession(s.id))); + await server.shutdown(); }); describe('SessionManager', () => { + let kernelManager: KernelManager; + let manager: SessionManager; + let session: Session.ISessionConnection; + + beforeEach(async () => { + kernelManager = new KernelManager({ standby: 'never' }); + manager = new SessionManager({ kernelManager, standby: 'never' }); + await manager.ready; + session = await startNew(manager); + await session.kernel!.info; + }); + + afterEach(() => { + manager.dispose(); + }); + describe('#constructor()', () => { it('should create a new session manager', () => { expect(manager instanceof SessionManager).toBe(true); @@ -96,14 +87,14 @@ describe('session/manager', () => { describe('#ready', () => { it('should resolve when the manager is ready', async () => { - await manager.ready; + await expect(manager.ready).resolves.not.toThrow(); }); }); describe('#running()', () => { it('should get the running sessions', async () => { await manager.refreshRunning(); - const running = toArray(manager.running()); + const running = Array.from(manager.running()); expect(running.length).toBeGreaterThan(0); }); }); @@ -113,7 +104,7 @@ describe('session/manager', () => { const promise = testEmission(manager.runningChanged, { test: (sender, args) => { expect(sender).toBe(manager); - expect(toArray(args).length).toBeGreaterThan(0); + expect(Array.from(args).length).toBeGreaterThan(0); } }); await startNew(manager); @@ -157,7 +148,7 @@ describe('session/manager', () => { // future is prematurely disposed. it('should refresh the list of session ids', async () => { await manager.refreshRunning(); - const running = toArray(manager.running()); + const running = Array.from(manager.running()); expect(running.length).toBeGreaterThan(0); }); }); @@ -230,7 +221,95 @@ describe('session/manager', () => { const session1 = manager.connectTo({ model: session0.model }); const emission = testEmission(session1.disposed); await session0.shutdown(); - await emission; + await expect(emission).resolves.not.toThrow(); + }); + }); + }); + + describe('NoopManager', () => { + let manager: SessionManager.NoopManager; + let kernelManager: KernelManager.NoopManager; + + beforeEach(async () => { + kernelManager = new KernelManager.NoopManager({ standby: 'never' }); + await kernelManager.parentReady; + manager = new SessionManager.NoopManager({ + kernelManager, + standby: 'never' + }); + await manager.parentReady; + }); + + afterEach(() => { + manager.dispose(); + }); + + describe('#constructor()', () => { + it('should take the options as an argument', async () => { + manager.dispose(); + manager = new SessionManager.NoopManager({ + kernelManager, + standby: 'never' + }); + await manager.parentReady; + expect(manager instanceof SessionManager.NoopManager).toBe(true); + }); + }); + + describe('#serverSettings', () => { + it('should get the server settings', async () => { + manager.dispose(); + const serverSettings = ServerConnection.makeSettings(); + const standby = 'never'; + const token = serverSettings.token; + manager = new SessionManager.NoopManager({ + kernelManager, + serverSettings, + standby + }); + await manager.parentReady; + expect(manager.serverSettings.token).toBe(token); + }); + }); + + describe('#running()', () => { + it('should get the running sessions', async () => { + await manager.refreshRunning(); + expect(Array.from(manager.running()).length).toEqual(0); + }); + }); + + describe('#refreshRunning()', () => { + it('should update the running kernels', async () => { + await manager.refreshRunning(); + expect(Array.from(manager.running()).length).toEqual(0); + }); + }); + + describe('#startNew()', () => { + it('should throw an error', () => { + return expect(startNew(manager)).rejects.toThrow(); + }); + }); + + describe('#connectTo()', () => { + it('should throw an error', () => { + const model = { + id: UUID.uuid4(), + path: UUID.uuid4(), + name: UUID.uuid4(), + type: 'MYTEST', + kernel: { name: 'foo', id: UUID.uuid4() } + }; + return expect(() => { + manager.connectTo({ model }); + }).toThrow(); + }); + }); + + describe('shutdown()', () => { + it('should throw an error', () => { + return expect(manager.shutdown(UUID.uuid4())).rejects.toThrow(); }); }); }); diff --git a/packages/services/test/session/session.spec.ts b/packages/services/test/session/session.spec.ts index 6cdd75cc0b20..282543e6d71e 100644 --- a/packages/services/test/session/session.spec.ts +++ b/packages/services/test/session/session.spec.ts @@ -1,32 +1,26 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { - expectFailure, - flakyIt as it, - JupyterServer -} from '@jupyterlab/testutils'; -import { toArray } from '@lumino/algorithm'; +import { JupyterServer } from '@jupyterlab/testing'; import { UUID } from '@lumino/coreutils'; import { Session, SessionAPI } from '../../src'; import { createSessionModel, getRequestHandler, makeSettings } from '../utils'; -const server = new JupyterServer(); - -beforeAll(async () => { - await server.start(); -}); - -afterAll(async () => { - await server.shutdown(); -}); - describe('session', () => { let session: Session.IModel; + let server: JupyterServer; + + jest.retryTimes(3); beforeAll(async () => { + server = new JupyterServer(); + await server.start(); const sessions = await SessionAPI.listRunning(); await Promise.all(sessions.map(s => SessionAPI.shutdownSession(s.id))); + }, 30000); + + afterAll(async () => { + await server.shutdown(); }); afterEach(async () => { @@ -36,39 +30,35 @@ describe('session', () => { describe('Session.listRunning()', () => { it('should yield a list of valid session models', async () => { - expect(toArray(await SessionAPI.listRunning()).length).toBe(0); + expect(Array.from(await SessionAPI.listRunning()).length).toBe(0); const session = await SessionAPI.startSession({ name: UUID.uuid4(), path: UUID.uuid4(), type: 'test' }); - expect(toArray(await SessionAPI.listRunning())).toEqual([session]); + expect(Array.from(await SessionAPI.listRunning())).toEqual([session]); }); it('should throw an error for an invalid model', async () => { const data = { id: '1234', path: 'test' }; const serverSettings = getRequestHandler(200, data); - const list = SessionAPI.listRunning(serverSettings); - await expectFailure(list); + await expect(SessionAPI.listRunning(serverSettings)).rejects.toThrow(); }); it('should throw an error for another invalid model', async () => { const data = [{ id: '1234', kernel: { id: '', name: '' }, path: '' }]; const serverSettings = getRequestHandler(200, data); - const list = SessionAPI.listRunning(serverSettings); - await expectFailure(list); + await expect(SessionAPI.listRunning(serverSettings)).rejects.toThrow(); }); it('should fail for wrong response status', async () => { const serverSettings = getRequestHandler(201, [createSessionModel()]); - const list = SessionAPI.listRunning(serverSettings); - await expectFailure(list); + await expect(SessionAPI.listRunning(serverSettings)).rejects.toThrow(); }); it('should fail for error response status', async () => { const serverSettings = getRequestHandler(500, {}); - const list = SessionAPI.listRunning(serverSettings); - await expectFailure(list, ''); + await expect(SessionAPI.listRunning(serverSettings)).rejects.toThrow(); }); }); @@ -98,33 +88,26 @@ describe('session', () => { it('should fail for wrong response status', async () => { const sessionModel = createSessionModel(); const serverSettings = getRequestHandler(200, sessionModel); - const sessionPromise = SessionAPI.startSession( - sessionModel as any, - serverSettings - ); - await expectFailure(sessionPromise); + await expect( + SessionAPI.startSession(sessionModel as any, serverSettings) + ).rejects.toThrow(); }); it('should fail for error response status', async () => { const serverSettings = getRequestHandler(500, {}); const sessionModel = createSessionModel(); - const sessionPromise = SessionAPI.startSession( - sessionModel as any, - serverSettings - ); - await expectFailure(sessionPromise, ''); + await expect( + SessionAPI.startSession(sessionModel as any, serverSettings) + ).rejects.toThrow(); }); it('should fail for wrong response model', async () => { const sessionModel = createSessionModel(); (sessionModel as any).path = 1; const serverSettings = getRequestHandler(201, sessionModel); - const sessionPromise = SessionAPI.startSession( - sessionModel as any, - serverSettings - ); - const msg = `Property 'path' is not of type 'string'`; - await expectFailure(sessionPromise, msg); + await expect( + SessionAPI.startSession(sessionModel as any, serverSettings) + ).rejects.toThrow(/Property 'path' is not of type 'string'/); }); it('should handle a deprecated response model', async () => { @@ -151,11 +134,15 @@ describe('session', () => { name: UUID.uuid4(), type: 'test' }); - await SessionAPI.shutdownSession(session.id); + await expect( + SessionAPI.shutdownSession(session.id) + ).resolves.not.toThrow(); }); - it('should handle a 404 status', () => { - return SessionAPI.shutdownSession(UUID.uuid4()); + it('should handle a 404 status', async () => { + await expect( + SessionAPI.shutdownSession(UUID.uuid4()) + ).resolves.not.toThrow(); }); }); }); diff --git a/packages/services/test/session/validate.spec.ts b/packages/services/test/session/validate.spec.ts index 20f0f76335ed..b4e60d227d58 100644 --- a/packages/services/test/session/validate.spec.ts +++ b/packages/services/test/session/validate.spec.ts @@ -17,7 +17,9 @@ describe('session/validate', () => { name: '', type: '' }; - validateModel(model); + expect(() => { + validateModel(model); + }).not.toThrow(); }); it('should fail on missing data', () => { @@ -27,7 +29,7 @@ describe('session/validate', () => { path: 'bar', name: '' }; - expect(() => validateModel(model)).toThrowError(); + expect(() => validateModel(model)).toThrow(); }); }); @@ -41,7 +43,9 @@ describe('session/validate', () => { } }; updateLegacySessionModel(model); - validateModel(model); + expect(() => { + validateModel(model); + }).not.toThrow(); }); }); }); diff --git a/packages/services/test/setting/manager.spec.ts b/packages/services/test/setting/manager.spec.ts index 98595797e13f..e6d318fb8ba6 100644 --- a/packages/services/test/setting/manager.spec.ts +++ b/packages/services/test/setting/manager.spec.ts @@ -1,14 +1,14 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { JupyterServer } from '@jupyterlab/testutils'; +import { JupyterServer } from '@jupyterlab/testing'; import { ServerConnection, SettingManager } from '../../src'; const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); diff --git a/packages/services/test/target.ts b/packages/services/test/target.ts index 09f0461770ae..b464167f5a2f 100644 --- a/packages/services/test/target.ts +++ b/packages/services/test/target.ts @@ -4,7 +4,7 @@ declare let define: any; if (typeof define !== 'function') { - // @ts-expect-error + // @ts-expect-error Import of a untyped module const define = require('amdefine')(module); // eslint-disable-line @typescript-eslint/no-unused-vars } diff --git a/packages/services/test/terminal/manager.spec.ts b/packages/services/test/terminal/manager.spec.ts index 4c39e42316f5..87f4e182d1b3 100644 --- a/packages/services/test/terminal/manager.spec.ts +++ b/packages/services/test/terminal/manager.spec.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { JupyterServer, testEmission } from '@jupyterlab/testutils'; -import { toArray } from '@lumino/algorithm'; +import { JupyterServer, testEmission } from '@jupyterlab/testing'; import { ServerConnection, Terminal, @@ -14,30 +13,30 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); }); describe('terminal', () => { - let manager: Terminal.IManager; - - beforeEach(async () => { - manager = new TerminalManager({ standby: 'never' }); - await manager.ready; - }); - - afterEach(() => { - manager.dispose(); - }); - afterAll(async () => { const models = await TerminalAPI.listRunning(); await Promise.all(models.map(m => TerminalAPI.shutdownTerminal(m.name))); }); describe('TerminalManager', () => { + let manager: Terminal.IManager; + + beforeEach(async () => { + manager = new TerminalManager({ standby: 'never' }); + await manager.ready; + }); + + afterEach(() => { + manager.dispose(); + }); + describe('#constructor()', () => { it('should accept no options', async () => { const manager = new TerminalManager({ standby: 'never' }); @@ -80,8 +79,8 @@ describe('terminal', () => { }); describe('#ready', () => { - it('should resolve when the manager is ready', () => { - return manager.ready; + it('should resolve when the manager is ready', async () => { + await expect(manager.ready).resolves.not.toThrow(); }); }); @@ -95,7 +94,7 @@ describe('terminal', () => { it('should give an iterator over the list of running models', async () => { await TerminalAPI.startNew(); await manager.refreshRunning(); - const running = toArray(manager.running()); + const running = Array.from(manager.running()); expect(running.length).toBeGreaterThan(0); }); }); @@ -148,7 +147,7 @@ describe('terminal', () => { const emission = testEmission(manager.runningChanged, { test: (sender, args) => { expect(sender).toBe(manager); - expect(toArray(args).length).toBeGreaterThan(0); + expect(Array.from(args).length).toBeGreaterThan(0); } }); await manager.startNew(); @@ -158,10 +157,10 @@ describe('terminal', () => { describe('#refreshRunning()', () => { it('should update the running session models', async () => { - const before = toArray(manager.running()).length; + const before = Array.from(manager.running()).length; const model = await TerminalAPI.startNew(); await manager.refreshRunning(); - const running = toArray(manager.running()); + const running = Array.from(manager.running()); expect(running.length).toBe(before + 1); let found = false; running.map(m => { @@ -173,4 +172,74 @@ describe('terminal', () => { }); }); }); + + describe('NoopManager', () => { + let manager: TerminalManager.NoopManager; + + beforeEach(async () => { + manager = new TerminalManager.NoopManager({ standby: 'never' }); + await manager.parentReady; + }); + + afterEach(() => { + manager.dispose(); + }); + + describe('#constructor()', () => { + it('should take the options as an argument', async () => { + manager.dispose(); + manager = new TerminalManager.NoopManager({ + standby: 'never' + }); + await manager.parentReady; + expect(manager instanceof TerminalManager.NoopManager).toBe(true); + }); + }); + + describe('#serverSettings', () => { + it('should get the server settings', async () => { + manager.dispose(); + const serverSettings = ServerConnection.makeSettings(); + const standby = 'never'; + const token = serverSettings.token; + manager = new TerminalManager.NoopManager({ serverSettings, standby }); + await manager.parentReady; + expect(manager.serverSettings.token).toBe(token); + }); + }); + + describe('#running()', () => { + it('should get the running sessions', async () => { + await manager.refreshRunning(); + expect(Array.from(manager.running()).length).toEqual(0); + }); + }); + + describe('#refreshRunning()', () => { + it('should update the running kernels', async () => { + await manager.refreshRunning(); + expect(Array.from(manager.running()).length).toEqual(0); + }); + }); + + describe('#startNew()', () => { + it('should throw an error', () => { + return expect(manager.startNew()).rejects.toThrow(); + }); + }); + + describe('#connectTo()', () => { + it('should throw an error', () => { + return expect(() => { + manager.connectTo({ model: { name: 'abcd' } }); + }).toThrow(); + }); + }); + + describe('shutdown()', () => { + it('should throw an error', () => { + return expect(manager.shutdown('1234')).rejects.toThrow(); + }); + }); + }); }); diff --git a/packages/services/test/terminal/terminal.spec.ts b/packages/services/test/terminal/terminal.spec.ts index faf940c47719..88b2dbb411c6 100644 --- a/packages/services/test/terminal/terminal.spec.ts +++ b/packages/services/test/terminal/terminal.spec.ts @@ -2,7 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { PageConfig } from '@jupyterlab/coreutils'; -import { JupyterServer, testEmission } from '@jupyterlab/testutils'; +import { JupyterServer, testEmission } from '@jupyterlab/testing'; import { Terminal, TerminalManager } from '../../src'; import { handleRequest } from '../utils'; @@ -10,7 +10,7 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); @@ -50,7 +50,7 @@ describe('terminal', () => { } }); session.send({ type: 'stdin', content: ['cd\r'] }); - await emission; + await expect(emission).resolves.not.toThrow(); }); }); @@ -99,8 +99,10 @@ describe('terminal', () => { }); describe('#send()', () => { - it('should send a message to the socket', async () => { - session.send({ type: 'stdin', content: [1, 2] }); + it('should send a message to the socket', () => { + expect(() => { + session.send({ type: 'stdin', content: [1, 2] }); + }).not.toThrow(); }); }); @@ -117,12 +119,12 @@ describe('terminal', () => { describe('#shutdown()', () => { it('should shut down the terminal session', async () => { session = await manager.startNew(); - await session.shutdown(); + await expect(session.shutdown()).resolves.not.toThrow(); }); - it('should handle a 404 status', () => { + it('should handle a 404 status', async () => { handleRequest(defaultSession, 404, {}); - return defaultSession.shutdown(); + await expect(defaultSession.shutdown()).resolves.not.toThrow(); }); }); }); diff --git a/packages/services/test/user/user.spec.ts b/packages/services/test/user/user.spec.ts index d0dcdd235842..d470ebea7940 100644 --- a/packages/services/test/user/user.spec.ts +++ b/packages/services/test/user/user.spec.ts @@ -1,14 +1,14 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { JupyterServer } from '@jupyterlab/testutils'; +import { JupyterServer } from '@jupyterlab/testing'; import { ServerConnection, UserManager } from '../../src'; const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); diff --git a/packages/services/test/utils.spec.ts b/packages/services/test/utils.spec.ts index c8bbe2381162..f1daa49591d1 100644 --- a/packages/services/test/utils.spec.ts +++ b/packages/services/test/utils.spec.ts @@ -1,11 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { - expectFailure, - isFulfilled, - testEmission -} from '@jupyterlab/testutils'; +import { expectFailure, isFulfilled, testEmission } from '@jupyterlab/testing'; import { PromiseDelegate } from '@lumino/coreutils'; import { Signal } from '@lumino/signaling'; @@ -13,7 +9,7 @@ describe('test/utils', () => { describe('testEmission', () => { it('should resolve to the given value', async () => { const owner = {}; - const x = new Signal<{}, number>(owner); + const x = new Signal(owner); const emission = testEmission(x, { value: 'done' }); @@ -23,7 +19,7 @@ describe('test/utils', () => { it('should find the given emission', async () => { const owner = {}; - const x = new Signal<{}, number>(owner); + const x = new Signal(owner); const emission = testEmission(x, { find: (a, b) => b === 1, value: 'done' @@ -36,7 +32,7 @@ describe('test/utils', () => { it('should reject if the test throws an error', async () => { const owner = {}; - const x = new Signal<{}, number>(owner); + const x = new Signal(owner); const emission = testEmission(x, { find: (a, b) => b === 1, test: (a, b) => { @@ -52,7 +48,7 @@ describe('test/utils', () => { it('should resolve if the test succeeds', async () => { const owner = {}; - const x = new Signal<{}, number>(owner); + const x = new Signal(owner); const emission = testEmission(x, { find: (a, b) => b === 1, test: (a, b) => { diff --git a/packages/services/test/utils.ts b/packages/services/test/utils.ts index 188c8e7192a7..58d9bda7f90d 100644 --- a/packages/services/test/utils.ts +++ b/packages/services/test/utils.ts @@ -7,7 +7,6 @@ import { PromiseDelegate, UUID } from '@lumino/coreutils'; -import { Response } from 'node-fetch'; import WebSocket from 'ws'; import { Contents, @@ -98,6 +97,7 @@ export const KERNELSPECS: JSONObject = { */ export function getRequestHandler( status: number, + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types body: any ): ServerConnection.ISettings { const fetch = (info: RequestInfo, init: RequestInit) => { @@ -121,7 +121,8 @@ export interface IService { /** * Handle a single request with a mock response. */ -export function handleRequest(item: IService, status: number, body: any) { +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export function handleRequest(item: IService, status: number, body: any): void { // Store the existing fetch function. const oldFetch = item.serverSettings.fetch; @@ -169,7 +170,13 @@ class SocketTester implements IService { for (let retry = 0; retry <= 5; retry++) { try { port = getRandomInt(9000, 20000); - this._server = new WebSocket.Server({ port }); + this._server = new WebSocket.Server({ + port, + handleProtocols: () => { + return KernelMessage.supportedKernelWebSocketProtocols + .v1KernelWebsocketJupyterOrg; + } + }); } catch (err) { if (retry === 5) { throw err; @@ -291,7 +298,7 @@ export class KernelTester extends SocketTester { /** * Send the status from the server to the client. */ - sendStatus(msgId: string, status: Kernel.Status) { + sendStatus(msgId: string, status: Kernel.Status): string { return this.sendMessage({ msgId, msgType: 'status', @@ -303,7 +310,10 @@ export class KernelTester extends SocketTester { /** * Send an iopub stream message. */ - sendStream(msgId: string, content: KernelMessage.IStreamMsg['content']) { + sendStream( + msgId: string, + content: KernelMessage.IStreamMsg['content'] + ): string { return this.sendMessage({ msgId, msgType: 'stream', @@ -318,7 +328,7 @@ export class KernelTester extends SocketTester { sendDisplayData( msgId: string, content: KernelMessage.IDisplayDataMsg['content'] - ) { + ): string { return this.sendMessage({ msgId, msgType: 'display_data', @@ -333,7 +343,7 @@ export class KernelTester extends SocketTester { sendUpdateDisplayData( msgId: string, content: KernelMessage.IUpdateDisplayDataMsg['content'] - ) { + ): string { return this.sendMessage({ msgId, msgType: 'update_display_data', @@ -344,7 +354,10 @@ export class KernelTester extends SocketTester { /** * Send an iopub comm open message. */ - sendCommOpen(msgId: string, content: KernelMessage.ICommOpenMsg['content']) { + sendCommOpen( + msgId: string, + content: KernelMessage.ICommOpenMsg['content'] + ): string { return this.sendMessage({ msgId, msgType: 'comm_open', @@ -359,7 +372,7 @@ export class KernelTester extends SocketTester { sendCommClose( msgId: string, content: KernelMessage.ICommCloseMsg['content'] - ) { + ): string { return this.sendMessage({ msgId, msgType: 'comm_close', @@ -371,7 +384,10 @@ export class KernelTester extends SocketTester { /** * Send an iopub comm message. */ - sendCommMsg(msgId: string, content: KernelMessage.ICommMsgMsg['content']) { + sendCommMsg( + msgId: string, + content: KernelMessage.ICommMsgMsg['content'] + ): string { return this.sendMessage({ msgId, msgType: 'comm_msg', @@ -383,7 +399,7 @@ export class KernelTester extends SocketTester { sendExecuteResult( msgId: string, content: KernelMessage.IExecuteResultMsg['content'] - ) { + ): string { return this.sendMessage({ msgId, msgType: 'execute_result', @@ -395,7 +411,7 @@ export class KernelTester extends SocketTester { sendExecuteReply( msgId: string, content: KernelMessage.IExecuteReplyMsg['content'] - ) { + ): string { return this.sendMessage({ msgId, msgType: 'execute_reply', @@ -407,7 +423,7 @@ export class KernelTester extends SocketTester { sendKernelInfoReply( msgId: string, content: KernelMessage.IInfoReplyMsg['content'] - ) { + ): string { return this.sendMessage({ msgId, msgType: 'kernel_info_reply', @@ -419,7 +435,7 @@ export class KernelTester extends SocketTester { sendInputRequest( msgId: string, content: KernelMessage.IInputRequestMsg['content'] - ) { + ): string { return this.sendMessage({ msgId, msgType: 'input_request', @@ -433,7 +449,7 @@ export class KernelTester extends SocketTester { */ sendMessage( options: MakeOptional, 'session'> - ) { + ): string { const msg = KernelMessage.createMessage({ session: this.serverSessionId, ...options @@ -444,10 +460,16 @@ export class KernelTester extends SocketTester { } /** - * Send a kernel message from the server to the client. + * Send a kernel message from the server to the client with newest protocol. */ send(msg: KernelMessage.Message): void { - this.sendRaw(serialize(msg)); + this.sendRaw( + serialize( + msg, + KernelMessage.supportedKernelWebSocketProtocols + .v1KernelWebsocketJupyterOrg + ) + ); } /** @@ -492,7 +514,7 @@ export class KernelTester extends SocketTester { /** * Dispose the tester. */ - dispose() { + dispose(): void { if (this._kernel) { this._kernel.dispose(); this._kernel = null; @@ -502,6 +524,7 @@ export class KernelTester extends SocketTester { /** * Set up a new server websocket to pretend like it is a server kernel. + * Use the newest protocol. */ protected onSocket(sock: WebSocket): void { super.onSocket(sock); @@ -510,7 +533,11 @@ export class KernelTester extends SocketTester { if (msg instanceof Buffer) { msg = new Uint8Array(msg).buffer; } - const data = deserialize(msg); + const data = deserialize( + msg, + KernelMessage.supportedKernelWebSocketProtocols + .v1KernelWebsocketJupyterOrg + ); if (data.header.msg_type === 'kernel_info_request') { // First send status busy message. this.parentHeader = data.header; @@ -600,7 +627,10 @@ export class SessionTester extends SocketTester { /** * Send the status from the server to the client. */ - sendStatus(status: Kernel.Status, parentHeader?: KernelMessage.IHeader) { + sendStatus( + status: Kernel.Status, + parentHeader?: KernelMessage.IHeader + ): void { const msg = KernelMessage.createMessage({ msgType: 'status', channel: 'iopub', @@ -616,10 +646,16 @@ export class SessionTester extends SocketTester { } /** - * Send a kernel message from the server to the client. + * Send a kernel message from the server to the client with newest protocol. */ send(msg: KernelMessage.IMessage): void { - this.sendRaw(serialize(msg)); + this.sendRaw( + serialize( + msg, + KernelMessage.supportedKernelWebSocketProtocols + .v1KernelWebsocketJupyterOrg + ) + ); } /** @@ -631,6 +667,7 @@ export class SessionTester extends SocketTester { /** * Set up a new server websocket to pretend like it is a server kernel. + * Use the newest protocol. */ protected onSocket(sock: WebSocket): void { super.onSocket(sock); @@ -638,7 +675,11 @@ export class SessionTester extends SocketTester { if (msg instanceof Buffer) { msg = new Uint8Array(msg).buffer; } - const data = deserialize(msg); + const data = deserialize( + msg, + KernelMessage.supportedKernelWebSocketProtocols + .v1KernelWebsocketJupyterOrg + ); if (KernelMessage.isInfoRequestMsg(data)) { // First send status busy message. this.sendStatus('busy', data.header); @@ -677,7 +718,7 @@ export class TerminalTester extends SocketTester { /** * Register the message callback with the websocket server. */ - onMessage(cb: (msg: Terminal.IMessage) => void) { + onMessage(cb: (msg: Terminal.IMessage) => void): void { this._onMessage = cb; } @@ -709,7 +750,6 @@ export class TerminalTester extends SocketTester { * type B = MakeOptional * const x: B = {b: 'test'} */ -type MakeOptional = Pick> & - { - [P in Extract]?: T[P]; - }; +type MakeOptional = Pick> & { + [P in Extract]?: T[P]; +}; diff --git a/packages/services/test/workspace/manager.spec.ts b/packages/services/test/workspace/manager.spec.ts index 723ee97a1b04..c581dbb2e3a1 100644 --- a/packages/services/test/workspace/manager.spec.ts +++ b/packages/services/test/workspace/manager.spec.ts @@ -1,14 +1,14 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { JupyterServer } from '@jupyterlab/testutils'; +import { JupyterServer } from '@jupyterlab/testing'; import { ServerConnection, WorkspaceManager } from '../../src'; const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); diff --git a/packages/services/tsconfig.json b/packages/services/tsconfig.json index a0742e5969e1..a71022419cb0 100644 --- a/packages/services/tsconfig.json +++ b/packages/services/tsconfig.json @@ -15,9 +15,6 @@ { "path": "../nbformat" }, - { - "path": "../observables" - }, { "path": "../settingregistry" }, diff --git a/packages/services/tsconfig.test.json b/packages/services/tsconfig.test.json index 991e84c4a754..556052aa3738 100644 --- a/packages/services/tsconfig.test.json +++ b/packages/services/tsconfig.test.json @@ -8,9 +8,6 @@ { "path": "../nbformat" }, - { - "path": "../observables" - }, { "path": "../settingregistry" }, @@ -21,22 +18,7 @@ "path": "." }, { - "path": "../../testutils" - }, - { - "path": "../coreutils" - }, - { - "path": "../nbformat" - }, - { - "path": "../observables" - }, - { - "path": "../settingregistry" - }, - { - "path": "../statedb" + "path": "../testing" } ] } diff --git a/packages/services/typings/xmlhttprequest/xmlhttprequest.d.ts b/packages/services/typings/xmlhttprequest/xmlhttprequest.d.ts index 02c0c14cb497..7f985cc9382b 100644 --- a/packages/services/typings/xmlhttprequest/xmlhttprequest.d.ts +++ b/packages/services/typings/xmlhttprequest/xmlhttprequest.d.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + declare module 'xmlhttprequest' { export var XMLHttpRequest: XMLHttpRequest; } diff --git a/packages/services/webpack.config.js b/packages/services/webpack.config.js index ac4d8cd19beb..57175b20c507 100644 --- a/packages/services/webpack.config.js +++ b/packages/services/webpack.config.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const version = require('./package.json').version; const crypto = require('crypto'); diff --git a/packages/settingeditor-extension/package.json b/packages/settingeditor-extension/package.json index b89759308e53..b88f23b33400 100644 --- a/packages/settingeditor-extension/package.json +++ b/packages/settingeditor-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/settingeditor-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Setting Editor Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -28,7 +28,8 @@ "lib/*.js", "schema/*.json", "style/**/*.css", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -37,21 +38,21 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/codeeditor": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/settingeditor": "^3.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/statedb": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/disposable": "^1.10.0" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/codeeditor": "^4.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/settingeditor": "^4.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@jupyterlab/statedb": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/disposable": "^2.1.2" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/settingeditor-extension/src/index.ts b/packages/settingeditor-extension/src/index.ts index 64bbd8d9d118..952c5ee67b29 100644 --- a/packages/settingeditor-extension/src/index.ts +++ b/packages/settingeditor-extension/src/index.ts @@ -14,14 +14,17 @@ import { JupyterFrontEndPlugin } from '@jupyterlab/application'; import { - CommandToolbarButton, ICommandPalette, MainAreaWidget, - Toolbar, WidgetTracker } from '@jupyterlab/apputils'; import { IEditorServices } from '@jupyterlab/codeeditor'; -import { IFormComponentRegistry, launchIcon } from '@jupyterlab/ui-components'; +import { + CommandToolbarButton, + IFormRendererRegistry, + launchIcon, + Toolbar +} from '@jupyterlab/ui-components'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { IJSONSettingEditorTracker, @@ -57,11 +60,12 @@ type SettingEditorType = 'ui' | 'json'; */ const plugin: JupyterFrontEndPlugin = { id: '@jupyterlab/settingeditor-extension:form-ui', + description: 'Adds the interactive settings editor and provides its tracker.', requires: [ ISettingRegistry, IStateDB, ITranslator, - IFormComponentRegistry, + IFormRendererRegistry, ILabStatus ], optional: [ILayoutRestorer, ICommandPalette, IJSONSettingEditorTracker], @@ -78,7 +82,7 @@ function activate( registry: ISettingRegistry, state: IStateDB, translator: ITranslator, - editorRegistry: IFormComponentRegistry, + editorRegistry: IFormRendererRegistry, status: ILabStatus, restorer: ILayoutRestorer | null, palette: ICommandPalette | null, @@ -103,7 +107,7 @@ function activate( const openUi = async (args: { query: string }) => { if (tracker.currentWidget && !tracker.currentWidget.isDisposed) { if (!tracker.currentWidget.isAttached) { - shell.add(tracker.currentWidget); + shell.add(tracker.currentWidget, 'main', { type: 'Settings' }); } shell.activateById(tracker.currentWidget.id); return; @@ -149,7 +153,7 @@ function activate( editor.title.closable = true; void tracker.add(editor); - shell.add(editor); + shell.add(editor, 'main', { type: 'Settings' }); }; commands.addCommand(CommandIDs.open, { @@ -174,7 +178,7 @@ function activate( if (args.label) { return args.label as string; } - return trans.__('Advanced Settings Editor'); + return trans.__('Settings Editor'); } }); @@ -194,6 +198,7 @@ function activate( */ const jsonPlugin: JupyterFrontEndPlugin = { id: '@jupyterlab/settingeditor-extension:plugin', + description: 'Adds the JSON settings editor and provides its tracker.', requires: [ ISettingRegistry, IEditorServices, @@ -244,7 +249,9 @@ function activateJSON( execute: async () => { if (tracker.currentWidget && !tracker.currentWidget.isDisposed) { if (!tracker.currentWidget.isAttached) { - shell.add(tracker.currentWidget); + shell.add(tracker.currentWidget, 'main', { + type: 'Advanced Settings' + }); } shell.activateById(tracker.currentWidget.id); return; @@ -303,9 +310,9 @@ function activateJSON( container.title.closable = true; void tracker.add(container); - shell.add(container); + shell.add(container, 'main', { type: 'Advanced Settings' }); }, - label: trans.__('Advanced JSON Settings Editor') + label: trans.__('Advanced Settings Editor') }); if (palette) { palette.addItem({ diff --git a/packages/settingeditor/.vscode/launch.json b/packages/settingeditor/.vscode/launch.json new file mode 100644 index 000000000000..66fb4b825a88 --- /dev/null +++ b/packages/settingeditor/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "attach", + "name": "Attach to jest", + // Usage: + // Open the parent directory in VSCode + // Run `jlpm test:debug:watch` in a terminal + // Run this debugging task + "port": 9229 + } + ] +} diff --git a/packages/settingeditor/babel.config.js b/packages/settingeditor/babel.config.js new file mode 100644 index 000000000000..fa81498e662b --- /dev/null +++ b/packages/settingeditor/babel.config.js @@ -0,0 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const defaultConfig = require('@jupyterlab/testing/lib/babel-config'); + +module.exports = defaultConfig; diff --git a/packages/settingeditor/jest.config.js b/packages/settingeditor/jest.config.js new file mode 100644 index 000000000000..cd234acbbdc0 --- /dev/null +++ b/packages/settingeditor/jest.config.js @@ -0,0 +1,7 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); +module.exports = func(__dirname); diff --git a/packages/settingeditor/package.json b/packages/settingeditor/package.json index 1354e80c6a45..4d6c47dc7135 100644 --- a/packages/settingeditor/package.json +++ b/packages/settingeditor/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/settingeditor", - "version": "3.6.6", + "version": "4.0.8", "description": "The JupyterLab default setting editor interface", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -27,41 +27,55 @@ "lib/*.js.map", "lib/*.js", "style/*.css", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", - "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", + "build:test": "tsc --build tsconfig.test.json", + "clean": "rimraf lib tsconfig.tsbuildinfo", "docs": "typedoc src", + "test": "jest", + "test:cov": "jest --collect-coverage", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/codeeditor": "^3.6.6", - "@jupyterlab/inspector": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/statedb": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/messaging": "^1.10.0", - "@lumino/polling": "^1.9.0", - "@lumino/signaling": "^1.10.0", - "@lumino/widgets": "^1.37.2", - "@rjsf/core": "^3.1.0", - "json-schema": "~0.4.0", - "react": "^17.0.1" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/codeeditor": "^4.0.8", + "@jupyterlab/inspector": "^4.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@jupyterlab/statedb": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/algorithm": "^2.0.1", + "@lumino/commands": "^2.1.3", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/messaging": "^2.0.1", + "@lumino/polling": "^2.1.2", + "@lumino/signaling": "^2.1.2", + "@lumino/widgets": "^2.3.0", + "@rjsf/core": "^5.1.0", + "@rjsf/utils": "^5.1.0", + "@rjsf/validator-ajv8": "^5.1.0", + "json-schema": "^0.4.0", + "react": "^18.2.0" }, "devDependencies": { - "@types/react": "^17.0.0", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "@types/react": "^18.0.26", + "@types/react-test-renderer": "^18.0.0", + "jest": "^29.2.0", + "react-test-renderer": "^18.2.0", "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "ts-jest": "^29.1.0", + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/settingeditor/src/InstructionsPlaceholder.tsx b/packages/settingeditor/src/InstructionsPlaceholder.tsx new file mode 100644 index 000000000000..a0fa26a337e9 --- /dev/null +++ b/packages/settingeditor/src/InstructionsPlaceholder.tsx @@ -0,0 +1,30 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import React from 'react'; + +import { ITranslator } from '@jupyterlab/translation'; + +type ISettingsEditorPlaceholderProps = { + translator: ITranslator; +}; + +export const SettingsEditorPlaceholder = ({ + translator +}: ISettingsEditorPlaceholderProps) => { + const trans = translator.load('jupyterlab'); + return ( +
    +
    +

    {trans.__('No Plugin Selected')}

    +

    + {trans.__( + 'Select a plugin from the list to view and edit its preferences.' + )} +

    +
    +
    + ); +}; diff --git a/packages/settingeditor/src/SettingsFormEditor.tsx b/packages/settingeditor/src/SettingsFormEditor.tsx index d9d35cd742f1..6e58b0c2c9bb 100644 --- a/packages/settingeditor/src/SettingsFormEditor.tsx +++ b/packages/settingeditor/src/SettingsFormEditor.tsx @@ -3,25 +3,24 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ +import React from 'react'; + import { showErrorMessage } from '@jupyterlab/apputils'; -import { caretDownIcon, caretRightIcon } from '@jupyterlab/ui-components'; import { ISettingRegistry, Settings } from '@jupyterlab/settingregistry'; import { ITranslator } from '@jupyterlab/translation'; -import { reduce } from '@lumino/algorithm'; -import { JSONExt, ReadonlyPartialJSONObject } from '@lumino/coreutils'; +import { FormComponent } from '@jupyterlab/ui-components'; +import { + JSONExt, + PartialJSONObject, + ReadonlyJSONObject, + ReadonlyPartialJSONObject +} from '@lumino/coreutils'; import { Debouncer } from '@lumino/polling'; -import Form, { - ArrayFieldTemplateProps, - Field, - FieldTemplateProps, - IChangeEvent, - ObjectFieldTemplateProps, - UiSchema, - utils -} from '@rjsf/core'; +import { IChangeEvent } from '@rjsf/core'; +import validatorAjv8 from '@rjsf/validator-ajv8'; +import { Field, UiSchema } from '@rjsf/utils'; import { JSONSchema7 } from 'json-schema'; -import React from 'react'; -import { PluginList } from './pluginlist'; +import { Button } from '@jupyterlab/ui-components'; /** * Indentation to use when saving the settings as JSON document. @@ -45,17 +44,7 @@ export namespace SettingsFormEditor { /** * Dictionary used for custom field renderers in the form. */ - renderers: { [id: string]: Field }; - - /** - * Whether the form is collapsed or not. - */ - isCollapsed: boolean; - - /** - * Callback with the collapse state value. - */ - onCollapseChange: (v: boolean) => void; + renderers: { [id: string]: { [property: string]: Field } }; /** * Translator object @@ -103,20 +92,6 @@ export namespace SettingsFormEditor { * Filtered schema */ filteredSchema?: ISettingRegistry.ISchema; - /** - * Field template - */ - fieldTemplate?: React.StatelessComponent>; - /** - * Array Field template - */ - arrayFieldTemplate?: React.StatelessComponent>; - /** - * Object Field template - */ - objectFieldTemplate?: React.StatelessComponent< - ObjectFieldTemplateProps - >; /** * Form context */ @@ -124,247 +99,6 @@ export namespace SettingsFormEditor { } } -/** - * Template to allow for custom buttons to re-order/remove entries in an array. - * Necessary to create accessible buttons. - */ -const CustomArrayTemplateFactory = ( - translator: ITranslator -): React.FC => { - const trans = translator.load('jupyterlab'); - - const factory = (props: ArrayFieldTemplateProps) => { - return ( -
    - - - {props.items.map(item => { - return ( -
    - {item.children} -
    - - - -
    -
    - ); - })} - {props.canAdd && ( - - )} -
    - ); - }; - factory.displayName = 'JupyterLabArrayTemplate'; - return factory; -}; - -/** - * Template with custom add button, necessary for accessiblity and internationalization. - */ -const CustomObjectTemplateFactory = ( - translator: ITranslator -): React.FC => { - const trans = translator.load('jupyterlab'); - - const factory = (props: ObjectFieldTemplateProps) => { - const { TitleField, DescriptionField } = props; - return ( -
    - {(props.uiSchema['ui:title'] || props.title) && ( - - )} - {props.description && ( - - )} - {props.properties.map(property => property.content)} - {utils.canExpand(props.schema, props.uiSchema, props.formData) && ( - - )} -
    - ); - }; - factory.displayName = 'JupyterLabObjectTemplate'; - return factory; -}; - -/** - * Renders the modified indicator and errors - */ -const CustomTemplateFactory = ( - translator: ITranslator -): React.FC => { - const trans = translator.load('jupyterlab'); - - const factory = (props: FieldTemplateProps) => { - const { - formData, - schema, - label, - displayLabel, - id, - formContext, - errors, - rawErrors, - children, - onKeyChange, - onDropPropertyClick - } = props; - /** - * Determine if the field has been modified - * Schema Id is formatted as 'root_.' - * This logic parses out the field name to find the default value - * before determining if the field has been modified. - */ - const schemaIds = id.split('_'); - schemaIds.shift(); - const schemaId = schemaIds.join('.'); - let defaultValue; - if (schemaIds.length === 1) { - defaultValue = formContext.settings.default(schemaId); - } else if (schemaIds.length > 1) { - const allDefaultsForObject: any = {}; - allDefaultsForObject[schemaIds[0]] = formContext.settings.default( - schemaIds[0] - ); - defaultValue = reduce( - schemaIds, - (acc, val, i) => { - return acc?.[val]; - }, - allDefaultsForObject - ); - } - const isModified = - schemaId !== '' && - formData !== undefined && - defaultValue !== undefined && - !schema.properties && - schema.type !== 'array' && - !JSONExt.deepEqual(formData, defaultValue); - const isRoot = schemaId === ''; - - const needsDescription = - !isRoot && - schema.type != 'object' && - id != - 'jp-SettingsEditor-@jupyterlab/shortcuts-extension:shortcuts_shortcuts'; - - // While we can implement "remove" button for array items in array template, - // object templates do not provide a way to do this; instead we need to add - // buttons here (and first check if the field can be removed = is additional). - const isAdditional = schema.hasOwnProperty(utils.ADDITIONAL_PROPERTY_FLAG); - - return ( -
    - { - // Only show the modified indicator if there are no errors - isModified && !rawErrors &&
    - } - { - // Shows a red indicator for fields that have validation errors - rawErrors && ( -
    - ) - } -
    - {displayLabel && !isRoot && label && !isAdditional && ( -

    - {label} -

    - )} - {isAdditional && ( - onKeyChange(event.target.value)} - defaultValue={label} - /> - )} -
    - {children} -
    - {isAdditional && ( - - )} - {schema.description && needsDescription && ( -
    {schema.description}
    - )} - {isModified && schema.default !== undefined && ( -
    - {trans.__('Default: %1', schema.default?.toLocaleString())} -
    - )} -
    {errors}
    -
    -
    - ); - }; - factory.displayName = 'JupyterLabFieldTemplate'; - return factory; -}; - /** * A React component that prepares the settings for a * given plugin to be rendered in the FormEditor. @@ -376,15 +110,15 @@ export class SettingsFormEditor extends React.Component< constructor(props: SettingsFormEditor.IProps) { super(props); const { settings } = props; - this._formData = settings.composite; + this._formData = settings.composite as ReadonlyJSONObject; this.state = { isModified: settings.isModified, uiSchema: {}, filteredSchema: this.props.settings.schema, - fieldTemplate: CustomTemplateFactory(this.props.translator), - arrayFieldTemplate: CustomArrayTemplateFactory(this.props.translator), - objectFieldTemplate: CustomObjectTemplateFactory(this.props.translator), - formContext: { settings: this.props.settings } + formContext: { + defaultFormData: this.props.settings.default(), + settings: this.props.settings + } }; this.handleChange = this.handleChange.bind(this); this._debouncer = new Debouncer(this.handleChange); @@ -396,20 +130,17 @@ export class SettingsFormEditor extends React.Component< } componentDidUpdate(prevProps: SettingsFormEditor.IProps): void { - this._setUiSchema(prevProps.renderers); + this._setUiSchema(prevProps.renderers[prevProps.settings.id]); this._setFilteredSchema(prevProps.filteredValues); - if (prevProps.translator !== this.props.translator) { + if (prevProps.settings !== this.props.settings) { this.setState({ - fieldTemplate: CustomTemplateFactory(this.props.translator), - arrayFieldTemplate: CustomArrayTemplateFactory(this.props.translator), - objectFieldTemplate: CustomObjectTemplateFactory(this.props.translator) + formContext: { + settings: this.props.settings, + defaultFormData: this.props.settings.default() + } }); } - - if (prevProps.settings !== this.props.settings) { - this.setState({ formContext: { settings: this.props.settings } }); - } } componentWillUnmount(): void { @@ -418,12 +149,12 @@ export class SettingsFormEditor extends React.Component< /** * Handler for edits made in the form editor. - * @param data - Form data sent from the form editor */ handleChange(): void { // Prevent unnecessary save when opening settings that haven't been modified. if ( !this.props.settings.isModified && + this._formData && this.props.settings.isDefault(this._formData) ) { this.props.updateDirtyState(false); @@ -452,73 +183,52 @@ export class SettingsFormEditor extends React.Component< for (const field in this.props.settings.user) { await this.props.settings.remove(field); } - this._formData = this.props.settings.composite; + this._formData = this.props.settings.composite as ReadonlyJSONObject; this.setState({ isModified: false }); }; render(): JSX.Element { const trans = this.props.translator.load('jupyterlab'); - const icon = this.props.isCollapsed ? caretRightIcon : caretDownIcon; return ( -
    -
    { - this.props.onCollapseChange(!this.props.isCollapsed); - this.props.onSelect(this.props.settings.id); - }} - > -
    - -

    {this.props.settings.schema.title}

    -
    - {this.props.settings.schema.description} -
    -
    - {this.state.isModified && ( - - )} + <> +
    +

    + {this.props.settings.schema.title} +

    +
    + {this.state.isModified && ( + + )} +
    +
    + {this.props.settings.schema.description} +
    - {!this.props.isCollapsed && ( -
    - )} -
    + + ); } - /** - * Callback on plugin selection - * @param list Plugin list - * @param id Plugin id - */ - protected onSelect = (list: PluginList, id: string): void => { - if (id === this.props.settings.id) { - this.props.onCollapseChange(false); - } - }; - private _onChange = (e: IChangeEvent): void => { this.props.hasError(e.errors.length !== 0); - this._formData = e.formData; + this._formData = e.formData as ReadonlyJSONObject; if (e.errors.length === 0) { this.props.updateDirtyState(true); void this._debouncer.invoke(); @@ -527,18 +237,18 @@ export class SettingsFormEditor extends React.Component< }; private _setUiSchema(prevRenderers?: { [id: string]: Field }) { + const renderers = this.props.renderers[this.props.settings.id]; if ( - !prevRenderers || !JSONExt.deepEqual( - Object.keys(prevRenderers).sort(), - Object.keys(this.props.renderers).sort() + Object.keys(prevRenderers ?? {}).sort(), + Object.keys(renderers ?? {}).sort() ) ) { /** * Construct uiSchema to pass any custom renderers to the form editor. */ const uiSchema: UiSchema = {}; - for (const id in this.props.renderers) { + for (const id in this.props.renderers[this.props.settings.id]) { if ( Object.keys(this.props.settings.schema.properties ?? {}).includes(id) ) { @@ -576,6 +286,23 @@ export class SettingsFormEditor extends React.Component< } } + private _getFilteredFormData( + filteredSchema?: ISettingRegistry.ISchema + ): ReadonlyJSONObject { + if (!filteredSchema?.properties) { + return this._formData; + } + const filteredFormData = JSONExt.deepCopy( + this._formData as PartialJSONObject + ); + for (const field in filteredFormData) { + if (!filteredSchema.properties[field]) { + delete filteredFormData[field]; + } + } + return filteredFormData as ReadonlyJSONObject; + } + private _debouncer: Debouncer; - private _formData: any; + private _formData: ReadonlyJSONObject; } diff --git a/packages/settingeditor/src/inspector.ts b/packages/settingeditor/src/inspector.ts index 51b689ac6ffe..0040756adac8 100644 --- a/packages/settingeditor/src/inspector.ts +++ b/packages/settingeditor/src/inspector.ts @@ -120,7 +120,7 @@ class InspectorConnector extends DataConnector< return `**\`[${this._trans.__('syntax error')}]\`** *${error.message}*`; case 'type': return `**\`[${this._trans.__('type error')}]\`** - \`${error.dataPath}\` ${error.message}`; + \`${error.instancePath}\` ${error.message}`; default: return `**\`[${this._trans.__('error')}]\`** *${error.message}*`; } diff --git a/packages/settingeditor/src/jsonsettingeditor.tsx b/packages/settingeditor/src/jsonsettingeditor.tsx index aed63c6cac47..e95a2b52e2bb 100644 --- a/packages/settingeditor/src/jsonsettingeditor.tsx +++ b/packages/settingeditor/src/jsonsettingeditor.tsx @@ -3,22 +3,21 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -import { ReactWidget } from '@jupyterlab/apputils'; import { CodeEditor } from '@jupyterlab/codeeditor'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { IStateDB } from '@jupyterlab/statedb'; import { ITranslator, nullTranslator } from '@jupyterlab/translation'; -import { jupyterIcon } from '@jupyterlab/ui-components'; +import { ReactWidget } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { JSONExt, JSONObject, JSONValue } from '@lumino/coreutils'; import { Message } from '@lumino/messaging'; import { ISignal } from '@lumino/signaling'; -import { Widget } from '@lumino/widgets'; +import { SplitPanel, Widget } from '@lumino/widgets'; import * as React from 'react'; +import { SettingsEditorPlaceholder } from './InstructionsPlaceholder'; import { PluginEditor } from './plugineditor'; import { PluginList } from './pluginlist'; -import { SplitPanel } from './splitpanel'; /** * The ratio panes in the setting editor. @@ -46,7 +45,6 @@ export class JsonSettingEditor extends SplitPanel { spacing: 1 }); this.translator = options.translator || nullTranslator; - const trans = this.translator.load('jupyterlab'); this.addClass('jp-SettingEditor'); this.key = options.key; this.state = options.state; @@ -54,25 +52,7 @@ export class JsonSettingEditor extends SplitPanel { const { commands, editorFactory, rendermime } = options; const registry = (this.registry = options.registry); const instructions = (this._instructions = ReactWidget.create( - -

    - - - {trans.__('Settings')} - -

    - - {trans.__( - 'Select a plugin from the list to view and edit its preferences.' - )} - -
    + )); instructions.addClass('jp-SettingEditorInstructions'); const editor = (this._editor = new PluginEditor({ @@ -336,9 +316,8 @@ export class JsonSettingEditor extends SplitPanel { private _instructions: Widget; private _list: PluginList; private _saving = false; - private _state: JsonSettingEditor.ILayoutState = JSONExt.deepCopy( - DEFAULT_LAYOUT - ); + private _state: JsonSettingEditor.ILayoutState = + JSONExt.deepCopy(DEFAULT_LAYOUT); private _when: Promise; } diff --git a/packages/settingeditor/src/plugineditor.ts b/packages/settingeditor/src/plugineditor.ts index 7f8e4ad81e64..50c4a6419f90 100644 --- a/packages/settingeditor/src/plugineditor.ts +++ b/packages/settingeditor/src/plugineditor.ts @@ -38,13 +38,8 @@ export class PluginEditor extends Widget { super(); this.addClass(PLUGIN_EDITOR_CLASS); - const { - commands, - editorFactory, - registry, - rendermime, - translator - } = options; + const { commands, editorFactory, registry, rendermime, translator } = + options; this.translator = translator || nullTranslator; this._trans = this.translator.load('jupyterlab'); @@ -250,7 +245,10 @@ namespace Private { /** * Handle save errors. */ - export function onSaveError(reason: any, translator?: ITranslator): void { + export function onSaveError( + reason: Dialog.IError, + translator?: ITranslator + ): void { translator = translator || nullTranslator; const trans = translator.load('jupyterlab'); console.error(`Saving setting editor value failed: ${reason.message}`); diff --git a/packages/settingeditor/src/pluginlist.tsx b/packages/settingeditor/src/pluginlist.tsx index 89a97ccf57e6..d6629cdcb0c4 100644 --- a/packages/settingeditor/src/pluginlist.tsx +++ b/packages/settingeditor/src/pluginlist.tsx @@ -3,20 +3,25 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ +import React from 'react'; + +import { ReactWidget } from '@jupyterlab/apputils'; +import { ISettingRegistry, Settings } from '@jupyterlab/settingregistry'; +import { ITranslator, nullTranslator } from '@jupyterlab/translation'; import { + classes, FilterBox, IScore, - ReactWidget, + LabIcon, + settingsIcon, updateFilterFunction -} from '@jupyterlab/apputils'; -import { ISettingRegistry, Settings } from '@jupyterlab/settingregistry'; -import { ITranslator, nullTranslator } from '@jupyterlab/translation'; -import { classes, LabIcon, settingsIcon } from '@jupyterlab/ui-components'; +} from '@jupyterlab/ui-components'; import { StringExt } from '@lumino/algorithm'; import { PartialJSONObject } from '@lumino/coreutils'; import { Message } from '@lumino/messaging'; import { ISignal, Signal } from '@lumino/signaling'; -import React from 'react'; + +import type { SettingsEditor } from './settingseditor'; /** * The JupyterLab plugin schema key for the setting editor @@ -54,10 +59,12 @@ export class PluginList extends ReactWidget { }, this); this.mapPlugins = this.mapPlugins.bind(this); this.setFilter = this.setFilter.bind(this); - this.setFilter(updateFilterFunction(options.query ?? '', false, false)); + this.setFilter( + options.query ? updateFilterFunction(options.query, false, false) : null + ); this.setError = this.setError.bind(this); this._evtMousedown = this._evtMousedown.bind(this); - this._query = options.query; + this._query = options.query ?? ''; this._allPlugins = PluginList.sortPlugins(this.registry).filter(plugin => { const { schema } = plugin; @@ -89,7 +96,6 @@ export class PluginList extends ReactWidget { void loadSettings(); this._errors = {}; - this.selection = this._allPlugins[0].id; } /** @@ -120,7 +126,7 @@ export class PluginList extends ReactWidget { return false; } - get filter(): (item: ISettingRegistry.IPlugin) => string[] | null { + get filter(): SettingsEditor.PluginSearchFilter { return this._filter; } @@ -138,10 +144,7 @@ export class PluginList extends ReactWidget { /** * Signal that fires when search filter is updated so that settings panel can filter results. */ - get updateFilterSignal(): ISignal< - this, - (plugin: ISettingRegistry.IPlugin) => string[] | null - > { + get updateFilterSignal(): ISignal { return this._updateFilterSignal; } @@ -240,7 +243,7 @@ export class PluginList extends ReactWidget { * @returns - String array of properties that match the search results. */ getFilterString( - filter: (item: string) => boolean | Partial | null, + filter: (item: string) => Partial | null, props: ISettingRegistry.IProperty, definitions?: any, ref?: string @@ -319,20 +322,24 @@ export class PluginList extends ReactWidget { * @param filter Filter function passed by search bar based on search value. */ setFilter( - filter: (item: string) => boolean | Partial | null, + filter: ((item: string) => Partial | null) | null, query?: string ): void { - this._filter = (plugin: ISettingRegistry.IPlugin): string[] | null => { - if (filter(plugin.schema.title ?? '')) { - return null; - } - const filtered = this.getFilterString( - filter, - plugin.schema ?? {}, - plugin.schema.definitions - ); - return filtered; - }; + if (filter) { + this._filter = (plugin: ISettingRegistry.IPlugin): string[] | null => { + if (!filter || filter(plugin.schema.title ?? '')) { + return null; + } + const filtered = this.getFilterString( + filter, + plugin.schema ?? {}, + plugin.schema.definitions + ); + return filtered; + }; + } else { + this._filter = null; + } this._query = query; this._updateFilterSignal.emit(this._filter); this.update(); @@ -371,20 +378,22 @@ export class PluginList extends ReactWidget { const icon = this.getHint(ICON_KEY, this.registry, plugin); const iconClass = this.getHint(ICON_CLASS_KEY, this.registry, plugin); const iconTitle = this.getHint(ICON_LABEL_KEY, this.registry, plugin); - const filteredProperties = this._filter(plugin)?.map(fieldValue => { - const highlightedIndices = StringExt.matchSumOfSquares( - fieldValue.toLocaleLowerCase(), - this._query?.toLocaleLowerCase() ?? '' - ); - const highlighted = StringExt.highlight( - fieldValue, - highlightedIndices?.indices ?? [], - chunk => { - return {chunk}; - } - ); - return
  • {highlighted}
  • ; - }); + const filteredProperties = this._filter + ? this._filter(plugin)?.map(fieldValue => { + const highlightedIndices = StringExt.matchSumOfSquares( + fieldValue.toLocaleLowerCase(), + this._query?.toLocaleLowerCase() ?? '' + ); + const highlighted = StringExt.highlight( + fieldValue, + highlightedIndices?.indices ?? [], + chunk => { + return {chunk}; + } + ); + return
  • {highlighted}
  • ; + }) + : undefined; return (
    { + if (!this._filter) { + return false; + } const filtered = this._filter(plugin); return filtered === null || filtered.length > 0; }); @@ -468,12 +480,12 @@ export class PluginList extends ReactWidget { protected translator: ITranslator; private _changed = new Signal(this); private _errors: { [id: string]: boolean }; - private _filter: (item: ISettingRegistry.IPlugin) => string[] | null; + private _filter: SettingsEditor.PluginSearchFilter; private _query: string | undefined; private _handleSelectSignal = new Signal(this); private _updateFilterSignal = new Signal< this, - (plugin: ISettingRegistry.IPlugin) => string[] | null + SettingsEditor.PluginSearchFilter >(this); private _allPlugins: ISettingRegistry.IPlugin[] = []; private _settings: { [id: string]: Settings } = {}; diff --git a/packages/settingeditor/src/raweditor.ts b/packages/settingeditor/src/raweditor.ts index b418d6d2e6c2..30add320f43f 100644 --- a/packages/settingeditor/src/raweditor.ts +++ b/packages/settingeditor/src/raweditor.ts @@ -1,17 +1,16 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { CommandToolbarButton, Toolbar } from '@jupyterlab/apputils'; import { CodeEditor, CodeEditorWrapper } from '@jupyterlab/codeeditor'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { ITranslator, nullTranslator } from '@jupyterlab/translation'; +import { CommandToolbarButton, Toolbar } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { Message } from '@lumino/messaging'; import { ISignal, Signal } from '@lumino/signaling'; -import { BoxLayout, Widget } from '@lumino/widgets'; +import { BoxLayout, SplitPanel, Widget } from '@lumino/widgets'; import { createInspector } from './inspector'; -import { SplitPanel } from './splitpanel'; /** * A class name added to all raw editors. @@ -49,24 +48,24 @@ export class RawEditor extends SplitPanel { // Create read-only defaults editor. const defaults = (this._defaults = new CodeEditorWrapper({ - model: new CodeEditor.Model(), + editorOptions: { + config: { readOnly: true } + }, + model: new CodeEditor.Model({ mimeType: 'text/javascript' }), factory: editorFactory })); - defaults.editor.model.value.text = ''; - defaults.editor.model.mimeType = 'text/javascript'; - defaults.editor.setOption('readOnly', true); - // Create read-write user settings editor. const user = (this._user = new CodeEditorWrapper({ - model: new CodeEditor.Model(), - factory: editorFactory, - config: { lineNumbers: true } + editorOptions: { + config: { lineNumbers: true } + }, + model: new CodeEditor.Model({ mimeType: 'text/javascript' }), + factory: editorFactory })); user.addClass(USER_CLASS); - user.editor.model.mimeType = 'text/javascript'; - user.editor.model.value.changed.connect(this._onTextChanged, this); + user.editor.model.sharedModel.changed.connect(this._onTextChanged, this); // Create and set up an inspector. this._inspector = createInspector( @@ -76,7 +75,6 @@ export class RawEditor extends SplitPanel { ); this.addClass(RAW_EDITOR_CLASS); - // FIXME-TRANS: onSaveError must have an optional translator? this._onSaveError = options.onSaveError; this.addWidget(Private.defaultsEditor(defaults, this.translator)); this.addWidget( @@ -114,7 +112,10 @@ export class RawEditor extends SplitPanel { * Tests whether the settings have been modified and need saving. */ get isDirty(): boolean { - return this._user.editor.model.value.text !== this._settings?.raw ?? ''; + return ( + this._user.editor.model.sharedModel.getSource() !== this._settings?.raw ?? + '' + ); } /** @@ -149,8 +150,8 @@ export class RawEditor extends SplitPanel { this._onSettingsChanged(); } else { this._settings = null; - defaults.editor.model.value.text = ''; - user.editor.model.value.text = ''; + defaults.editor.model.sharedModel.setSource(''); + user.editor.model.sharedModel.setSource(''); } this.update(); @@ -181,16 +182,18 @@ export class RawEditor extends SplitPanel { return; } - super.dispose(); + this._defaults.model.dispose(); this._defaults.dispose(); + this._user.model.dispose(); this._user.dispose(); + super.dispose(); } /** * Revert the editor back to original settings. */ revert(): void { - this._user.editor.model.value.text = this.settings?.raw ?? ''; + this._user.editor.model.sharedModel.setSource(this.settings?.raw ?? ''); this._updateToolbar(false, false); } @@ -203,7 +206,7 @@ export class RawEditor extends SplitPanel { } const settings = this._settings; - const source = this._user.editor.model.value.text; + const source = this._user.editor.model.sharedModel.getSource(); return settings .save(source) @@ -224,25 +227,11 @@ export class RawEditor extends SplitPanel { this.update(); } - /** - * Handle `'update-request'` messages. - */ - protected onUpdateRequest(msg: Message): void { - const settings = this._settings; - const defaults = this._defaults; - const user = this._user; - - if (settings) { - defaults.editor.refresh(); - user.editor.refresh(); - } - } - /** * Handle text changes in the underlying editor. */ private _onTextChanged(): void { - const raw = this._user.editor.model.value.text; + const raw = this._user.editor.model.sharedModel.getSource(); const settings = this._settings; this.removeClass(ERROR_CLASS); @@ -272,8 +261,10 @@ export class RawEditor extends SplitPanel { const defaults = this._defaults; const user = this._user; - defaults.editor.model.value.text = settings?.annotatedDefaults() ?? ''; - user.editor.model.value.text = settings?.raw ?? ''; + defaults.editor.model.sharedModel.setSource( + settings?.annotatedDefaults() ?? '' + ); + user.editor.model.sharedModel.setSource(settings?.raw ?? ''); } private _updateToolbar(revert = this._canRevert, save = this._canSave): void { @@ -338,7 +329,7 @@ export namespace RawEditor { /** * A function the raw editor calls on save errors. */ - onSaveError: (reason: any) => void; + onSaveError: (reason: any, translator?: ITranslator) => void; /** * The setting registry used by the editor. diff --git a/packages/settingeditor/src/settingseditor.tsx b/packages/settingeditor/src/settingseditor.tsx index 89a32d4bb355..3cf07bb23cc7 100644 --- a/packages/settingeditor/src/settingseditor.tsx +++ b/packages/settingeditor/src/settingseditor.tsx @@ -1,9 +1,14 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import { ILabStatus } from '@jupyterlab/application'; -import { ReactWidget, showDialog } from '@jupyterlab/apputils'; +import { showDialog } from '@jupyterlab/apputils'; import { ISettingRegistry, Settings } from '@jupyterlab/settingregistry'; import { IStateDB } from '@jupyterlab/statedb'; import { ITranslator, nullTranslator } from '@jupyterlab/translation'; -import { IFormComponentRegistry } from '@jupyterlab/ui-components'; +import { IFormRendererRegistry, ReactWidget } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { IDisposable } from '@lumino/disposable'; import { Message } from '@lumino/messaging'; @@ -156,6 +161,13 @@ export namespace SettingsEditor { */ export type SaveState = 'started' | 'failed' | 'completed'; + /** + * + */ + export type PluginSearchFilter = + | ((plugin: ISettingRegistry.IPlugin) => string[] | null) + | null; + /** * Settings editor options */ @@ -163,7 +175,7 @@ export namespace SettingsEditor { /** * Form component registry */ - editorRegistry: IFormComponentRegistry; + editorRegistry: IFormRendererRegistry; /** * The state database key for the editor's state management. diff --git a/packages/settingeditor/src/settingspanel.tsx b/packages/settingeditor/src/settingspanel.tsx index f43598537176..5de1570c7ec3 100644 --- a/packages/settingeditor/src/settingspanel.tsx +++ b/packages/settingeditor/src/settingspanel.tsx @@ -3,14 +3,18 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -import { ISettingRegistry, Settings } from '@jupyterlab/settingregistry'; +import React, { useEffect, useState } from 'react'; + +import { Settings } from '@jupyterlab/settingregistry'; import { ITranslator } from '@jupyterlab/translation'; -import { IFormComponentRegistry } from '@jupyterlab/ui-components'; +import { IFormRendererRegistry } from '@jupyterlab/ui-components'; import { ISignal } from '@lumino/signaling'; -import React, { useEffect, useState } from 'react'; import { PluginList } from './pluginlist'; import { SettingsFormEditor } from './SettingsFormEditor'; +import { SettingsEditorPlaceholder } from './InstructionsPlaceholder'; +import type { Field } from '@rjsf/utils'; +import type { SettingsEditor } from './settingseditor'; export interface ISettingsPanelProps { /** * List of Settings objects that provide schema and values @@ -22,7 +26,7 @@ export interface ISettingsPanelProps { * Form component registry that provides renderers * for the form editor. */ - editorRegistry: IFormComponentRegistry; + editorRegistry: IFormRendererRegistry; /** * Handler for when selection change is triggered by scrolling @@ -54,16 +58,13 @@ export interface ISettingsPanelProps { /** * Signal that sends updated filter when search value changes. */ - updateFilterSignal: ISignal< - PluginList, - (plugin: ISettingRegistry.IPlugin) => string[] | null - >; + updateFilterSignal: ISignal; /** * If the settings editor is created with an initial search query, an initial * filter function is passed to the settings panel. */ - initialFilter: (item: ISettingRegistry.IPlugin) => string[] | null; + initialFilter: SettingsEditor.PluginSearchFilter; } /** @@ -81,18 +82,10 @@ export const SettingsPanel: React.FC = ({ translator, initialFilter }: ISettingsPanelProps): JSX.Element => { - const [expandedPlugin, setExpandedPlugin] = useState(null); - const [filterPlugin, setFilter] = useState< - (plugin: ISettingRegistry.IPlugin) => string[] | null - >(() => initialFilter); - - // Refs used to keep track of "selected" plugin based on scroll location - const editorRefs: { - [pluginId: string]: React.RefObject; - } = {}; - for (const setting of settings) { - editorRefs[setting.id] = React.useRef(null); - } + const [activePluginId, setActivePluginId] = useState(null); + const [filterPlugin, setFilter] = useState( + initialFilter ? () => initialFilter : null + ); const wrapperRef: React.RefObject = React.useRef(null); const editorDirtyStates: React.RefObject<{ [id: string]: boolean; @@ -101,34 +94,16 @@ export const SettingsPanel: React.FC = ({ useEffect(() => { const onFilterUpdate = ( list: PluginList, - newFilter: (plugin: ISettingRegistry.IPlugin) => string[] | null + newFilter: SettingsEditor.PluginSearchFilter ) => { - setFilter(() => newFilter); - for (const pluginSettings of settings) { - const filtered = newFilter(pluginSettings.plugin); - if (filtered === null || filtered.length > 0) { - setExpandedPlugin(pluginSettings.id); - break; - } - } + newFilter ? setFilter(() => newFilter) : setFilter(null); }; - // Set first visible plugin as expanded plugin on initial load. - for (const pluginSettings of settings) { - const filtered = filterPlugin(pluginSettings.plugin); - if (filtered === null || filtered.length > 0) { - setExpandedPlugin(pluginSettings.id); - break; - } - } - // When filter updates, only show plugins that match search. updateFilterSignal.connect(onFilterUpdate); const onSelectChange = (list: PluginList, pluginId: string) => { - setExpandedPlugin(expandedPlugin !== pluginId ? pluginId : null); - // Scroll to the plugin when a selection is made in the left panel. - editorRefs[pluginId]?.current?.scrollIntoView(true); + setActivePluginId(pluginId); }; handleSelectSignal?.connect?.(onSelectChange); @@ -138,46 +113,68 @@ export const SettingsPanel: React.FC = ({ }; }, []); - const updateDirtyStates = (id: string, dirty: boolean) => { - if (editorDirtyStates.current) { - editorDirtyStates.current[id] = dirty; - for (const editor in editorDirtyStates.current) { - if (editorDirtyStates.current[editor]) { - updateDirtyState(true); - return; + const updateDirtyStates = React.useCallback( + (id: string, dirty: boolean) => { + if (editorDirtyStates.current) { + editorDirtyStates.current[id] = dirty; + for (const editor in editorDirtyStates.current) { + if (editorDirtyStates.current[editor]) { + updateDirtyState(true); + return; + } } } - } - updateDirtyState(false); - }; + updateDirtyState(false); + }, + [editorDirtyStates, updateDirtyState] + ); + + const renderers = React.useMemo( + () => + Object.entries(editorRegistry.renderers).reduce<{ + [plugin: string]: { [property: string]: Field }; + }>((agg, [id, renderer]) => { + const splitPosition = id.lastIndexOf('.'); + const pluginId = id.substring(0, splitPosition); + const propertyName = id.substring(splitPosition + 1); + if (!agg[pluginId]) { + agg[pluginId] = {}; + } + if (!agg[pluginId][propertyName] && renderer.fieldRenderer) { + agg[pluginId][propertyName] = renderer.fieldRenderer; + } + return agg; + }, {}), + [editorRegistry] + ); + + if (!activePluginId && !filterPlugin) { + return ; + } return (
    {settings.map(pluginSettings => { // Pass filtered results to SettingsFormEditor to only display filtered fields. - const filtered = filterPlugin(pluginSettings.plugin); + const filtered = filterPlugin + ? filterPlugin(pluginSettings.plugin) + : null; // If filtered results are an array, only show if the array is non-empty. - if (filtered !== null && filtered.length === 0) { + if ( + (activePluginId && activePluginId !== pluginSettings.id) || + (filtered !== null && filtered.length === 0) + ) { return undefined; } return (
    { - if (!willCollapse) { - setExpandedPlugin(pluginSettings.id); - } else if (pluginSettings.id === expandedPlugin) { - setExpandedPlugin(null); - } - }} filteredValues={filtered} settings={pluginSettings} - renderers={editorRegistry.renderers} + renderers={renderers} hasError={(error: boolean) => { hasError(pluginSettings.id, error); }} diff --git a/packages/settingeditor/src/splitpanel.ts b/packages/settingeditor/src/splitpanel.ts deleted file mode 100644 index 79917037c3a3..000000000000 --- a/packages/settingeditor/src/splitpanel.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* ----------------------------------------------------------------------------- -| Copyright (c) Jupyter Development Team. -| Distributed under the terms of the Modified BSD License. -|----------------------------------------------------------------------------*/ - -import { SplitPanel } from '@lumino/widgets'; - -/** - * @deprecated alias for `SplitPanel` from `@lumino/widgets`, will be removed in JupyterLab 4.0. - * Please use `import { SplitPanel } from '@lumino/widgets';` instead. - */ -export { SplitPanel }; diff --git a/packages/settingeditor/src/tokens.ts b/packages/settingeditor/src/tokens.ts index 670c0c60f40f..76e518cd8cc5 100644 --- a/packages/settingeditor/src/tokens.ts +++ b/packages/settingeditor/src/tokens.ts @@ -6,14 +6,31 @@ import { Token } from '@lumino/coreutils'; import { JsonSettingEditor as JSONSettingEditor } from './jsonsettingeditor'; import { SettingsEditor } from './settingseditor'; -/* tslint:disable */ /** * The setting editor tracker token. */ export const ISettingEditorTracker = new Token( - '@jupyterlab/settingeditor:ISettingEditorTracker' + '@jupyterlab/settingeditor:ISettingEditorTracker', + `A widget tracker for the interactive setting editor. + Use this if you want to be able to iterate over and interact with setting editors + created by the application.` ); -/* tslint:enable */ + +/** + * The setting editor tracker token. + */ +export const IJSONSettingEditorTracker = new Token( + '@jupyterlab/settingeditor:IJSONSettingEditorTracker', + `A widget tracker for the JSON setting editor. + Use this if you want to be able to iterate over and interact with setting editors + created by the application.` +); + +/** + * A class that tracks the setting editor. + */ +export interface IJSONSettingEditorTracker + extends IWidgetTracker> {} /** * The setting editor tracker token. diff --git a/packages/settingeditor/style/base.css b/packages/settingeditor/style/base.css index e6476cead209..8f2a997035a5 100644 --- a/packages/settingeditor/style/base.css +++ b/packages/settingeditor/style/base.css @@ -11,6 +11,7 @@ --jp-private-settingeditor-toolbar-height: 28px; --jp-private-settingeditor-type-width: 75px; --jp-private-settingeditor-modifier-indent: 5px; + --jp-private-settingeditor-header-spacing: 8px; } .jp-SettingsPanel, @@ -18,9 +19,10 @@ min-width: 360px; min-height: 240px; background-color: var(--jp-layout-color0); + color: var(--jp-ui-font-color0); margin-top: -1px; outline: none; - color: var(--jp-content-font-color1) !important; + /* This is needed so that all font sizing of children done in ems is * relative to this base size */ font-size: var(--jp-ui-font-size1); @@ -40,29 +42,7 @@ background-color: var(--jp-border-color2); } -#json-setting-editor .jp-SettingEditorInstructions { - text-align: center; -} - -#json-setting-editor .jp-SettingEditorInstructions-icon { - display: inline-block; - height: 78px; - margin: 2px 5px 2px 8px; - width: 60px; -} - -#json-setting-editor .jp-SettingEditorInstructions-title { - color: var(--jp-ui-font-color0); - font-size: 32px; - font-weight: 200; - line-height: 78px; - vertical-align: top; -} - -#json-setting-editor .jp-SettingEditorInstructions-text { - color: var(--jp-ui-font-color0); - font-size: var(--jp-ui-font-size2); -} +/** Plugin list **/ .jp-PluginList { min-width: 175px; @@ -92,6 +72,7 @@ .jp-PluginList .jp-PluginList-header { border-bottom: var(--jp-border-width) solid var(--jp-border-color2); border-top: var(--jp-border-width) solid var(--jp-border-color2); + color: var(--jp-ui-font-color1); } .jp-PluginList .jp-PluginList-noResults, @@ -105,7 +86,7 @@ margin: 10px; border-bottom: var(--jp-border-width) solid var(--jp-border-color2); border-top: var(--jp-border-width) solid var(--jp-border-color2); - color: var(--jp-content-font-color1); + color: var(--jp-ui-font-color1); } .jp-PluginList .jp-SelectedIndicator { @@ -123,43 +104,60 @@ background-color: var(--jp-error-color0); } -.jp-PluginList button.jp-mod-selected.jp-ErrorPlugin span { - color: var(--jp-error-color0); +.jp-PluginList-icon { + display: flex; + height: 20px; + width: 20px; + margin-right: 3px; + position: relative; +} + +.jp-PluginList-wrapper > .jp-FilterBox { + margin: 8px 12px 0; } -.jp-PluginList button.jp-mod-selected span { - font-weight: var(--jp-content-heading-font-weight); - color: var(--jp-brand-color1); +.jp-PluginList mark { + background-color: transparent; + font-weight: bold; + color: var(--jp-ui-font-color1); } -.jp-FormComponent li span { +.jp-PluginList-entry { + display: flex; + flex-direction: column; + border: 1px solid transparent; + background: transparent; overflow: hidden; + padding: 4px 0 4px 4px; + white-space: nowrap; } -.jp-SettingEditor-header { - font-size: var(--jp-content-font-size4); - font-weight: var(--jp-content-heading-font-weight); - color: var(--jp-ui-font-color0); - padding: 20px 0 10px 20px; - border-bottom: 1px solid var(--jp-border-color2); - position: sticky; - top: 0; - z-index: 999; - background-color: var(--jp-layout-color0); +.jp-PluginList-entry:hover { + background: var(--jp-layout-color1); } -ul.jp-PluginList li.jp-mod-selected span.jp-PluginList-icon.jp-FileIcon { - background-image: var(--jp-icon-file-selected); +.jp-PluginList-entry li { + margin-left: 27px; + margin-top: 5px; + color: var(--jp-ui-font-color1); + overflow-x: hidden; + text-overflow: ellipsis; } -.jp-PluginList-icon { +.jp-PluginList-entry-label { display: flex; - height: 20px; - width: 20px; - margin-right: 3px; - position: relative; } +.jp-PluginList-entry-label-text { + text-overflow: ellipsis; + overflow-x: hidden; + white-space: nowrap; + color: var(--jp-ui-font-color1); + line-height: var(--jp-cell-collapser-min-height); +} + +/** Raw editor **/ + .jp-SettingsRawEditor .jp-Toolbar { color: var(--jp-ui-font-color0); font-size: var(--jp-ui-font-size1); @@ -176,19 +174,6 @@ ul.jp-PluginList li.jp-mod-selected span.jp-PluginList-icon.jp-FileIcon { align-items: center; } -.jp-ToolbarButtonComponent-label - .jp-SettingsRawEditor.jp-mod-error - .jp-Toolbar-item.jp-BugIcon::after { - color: red; - content: '\25CF'; /* Unicode circle character (error dot) */ - font-size: 7px; - width: 100%; - height: 100%; - position: absolute; - top: 4px; - left: 6px; -} - .jp-SettingsRawEditor .jp-Inspector { border-top: 2px solid var(--jp-layout-color2); min-height: var(--jp-private-settingeditor-debug-height); @@ -204,40 +189,11 @@ ul.jp-PluginList li.jp-mod-selected span.jp-PluginList-icon.jp-FileIcon { text-align: right; } -.jp-SettingsPanel fieldset input, -.jp-SettingsPanel fieldset select, -.jp-SettingsPanel fieldset textarea { - font-size: var(--jp-content-font-size2); - border-color: var(--jp-input-border-color); - border-style: solid; - border-radius: var(--jp-border-radius); - border-width: 1px; - padding: 6px 8px; - background: none; - color: var(--jp-content-font-color0); - height: inherit; -} - -.jp-SettingsPanel fieldset input[type='checkbox'] { - position: relative; - top: 2px; - margin-left: 0; -} - -/** copy of `input.jp-mod-styled:focus` style */ -.jp-SettingsPanel fieldset input:focus, -.jp-SettingsPanel fieldset select:focus, -.jp-SettingsPanel fieldset textarea:focus { - -moz-outline-radius: unset; - outline: var(--jp-border-width) solid var(--md-blue-500); - outline-offset: -1px; - box-shadow: inset 0 0 4px var(--md-blue-300); +.jp-SettingsRawEditor .cm-editor { + height: 100%; } -.jp-SettingsPanel .checkbox label { - cursor: pointer; - font-size: var(--jp-content-font-size1); -} +/** Panel **/ .jp-SettingsPanel .checkbox p { font-size: var(--jp-content-font-size1); @@ -248,283 +204,84 @@ ul.jp-PluginList li.jp-mod-selected span.jp-PluginList-icon.jp-FileIcon { flex-direction: column-reverse; } -.jp-SettingsPanel .checkbox .field-description { - /* Disable default description field for checkbox: - because other widgets do not have description fields, - we add descriptions to each widget on the field level. - */ - display: none; -} - -.jp-SettingsPanel button[type='submit'] { - display: none; -} - .jp-SettingsPanel .form-group { display: flex; padding: 4px 8px 4px var(--jp-private-settingeditor-modifier-indent); margin-top: 5px; } -.jp-SettingsPanel .jp-objectFieldWrapper .form-group { - padding: 2px 8px 2px var(--jp-private-settingeditor-modifier-indent); - margin-top: 2px; -} - -.jp-ArrayOperations { - margin-left: 8px; -} - -.jp-SettingsPanel .jp-FormGroup-content { - display: flex; - align-items: center; - flex-wrap: wrap; -} - -.jp-SettingsPanel .jp-FormGroup-contentItem { - margin-left: 7px; -} - -.jp-SettingsPanel .jp-FormGroup-description { - flex-basis: 100%; - padding: 4px 7px; -} - -.jp-SettingsPanel .jp-FormGroup-default { - flex-basis: 100%; - padding: 4px 7px; -} - -.jp-SettingsPanel #root__description { - display: none; -} - -.jp-SettingsPanel fieldset { - border: none; - padding: 0; -} - -.jp-SettingsPanel fieldset:not(:first-child) { - margin-left: 7px; -} - -.jp-SettingsPanel .jp-SaveSettingsBanner { - position: absolute; - bottom: 0; +.jp-SettingsPanel .jp-SettingsEditor { padding: 20px; - width: 100%; - background: var(--jp-border-color3); -} - -.jp-SettingsPanel .jp-SaveSettingsBanner button { - box-shadow: none; - outline: none; - border: none; - color: var(--jp-brand-color1); - font-size: var(--jp-ui-font-size1); - cursor: pointer; } -.jp-SettingsPanel .jp-SaveSettingsBanner button:hover { - color: var(--jp-brand-color0); -} - -.jp-SettingsPanel .form-group.small-field:hover { - background: var(--jp-border-color3); -} - -.jp-SettingsPanel button.jp-mod-styled { - cursor: pointer; -} - -.jp-SettingsPanel button.jp-mod-styled:disabled { - cursor: not-allowed; - opacity: 0.5; -} - -.jp-SettingsPanel .array-item button { - margin: 2px; -} - -.jp-SettingsPanel .array-item { - border: 1px solid var(--jp-border-color2); - border-radius: 4px; - margin: 4px; -} - -.jp-SettingsPanel .field-array-of-string .array-item { - /* Display `jp-ArrayOperations` buttons side-by-side with content except - for small screens where flex-wrap will place them one below the other. - */ - display: flex; - align-items: center; - flex-wrap: wrap; -} - -.jp-SettingsPanel .jp-root > fieldset > legend { - display: none; -} - -.jp-SettingsPanel .jp-root > fieldset > p { - display: none; -} - -.jp-SettingsPanel .jp-SettingsHeader h2 { - font-size: var(--jp-content-font-size3); - color: var(--jp-ui-font-color0); - font-weight: 300; - margin: 1em; -} - -.jp-SettingsPanel .jp-SettingsHeader-description { - font-size: var(--jp-content-font-size2); - color: var(--jp-ui-font-color1); - font-weight: 200; - margin: 1em; - line-height: var(--jp-content-font-size3); -} - -.jp-SettingsPanel legend { - font-size: var(--jp-content-font-size2); - color: var(--jp-ui-font-color0); - flex-basis: 100%; - padding: 4px 0; - font-weight: var(--jp-content-header-font-weight); - border-bottom: 1px solid var(--jp-border-color2); -} - -.jp-SettingsPanel .field-description { - padding: 4px 0; - white-space: pre-wrap; -} - -.jp-SettingsPanel .jp-SettingsTitle { - display: flex; - align-items: center; - padding-left: 1em; -} - -.jp-SettingsPanel .jp-SettingsTitle-caret { - width: 2em; - flex-shrink: 0; +.jp-SettingsPanel { + overflow-y: auto; + height: 100%; } .jp-SettingsForm { position: relative; } -.jp-SettingsPanel .jp-SettingsHeader { - display: flex; - flex: auto; - justify-content: space-between; - cursor: pointer; - border: 1px solid var(--jp-border-color2); -} - -.jp-PluginList .jp-FilterBox { - margin: 8px 12px 0px 12px; -} - -.jp-PluginList mark { - background-color: transparent; - font-weight: bold; - color: var(--jp-ui-font-color1); -} - -.jp-PluginList-entry { - display: flex; - flex-direction: column; - border: 1px solid transparent; - background: transparent; - overflow: hidden; - padding: 4px 0 4px 4px; - white-space: nowrap; -} - -.jp-PluginList-entry:hover { - background: var(--jp-layout-color1); -} - -.jp-PluginList-entry li { - margin-left: 27px; - margin-top: 5px; - color: var(--jp-ui-font-color1); - overflow-x: hidden; - text-overflow: ellipsis; +.jp-SettingsForm > .rjsf > .form-group { + padding-top: 0; + margin-top: 0; } -.jp-PluginList-entry-label { - display: flex; -} +/** Settings header **/ -.jp-PluginList-entry-label-text { - text-overflow: ellipsis; - overflow-x: hidden; - white-space: nowrap; - color: var(--jp-content-font-color1); - line-height: var(--jp-cell-collapser-min-height); +.jp-SettingsHeader { + display: grid; + grid-template: + 'title buttonbar' + 'description buttonbar'; + grid-template-columns: 1fr max-content; + padding: 0 var(--jp-private-settingeditor-header-spacing); + border-bottom: 1px solid var(--jp-border-color2); } -.jp-SettingsPanel .jp-SettingsHeader-Name { - text-transform: inherit; +.jp-SettingsHeader-title { font-size: var(--jp-content-font-size3); + color: var(--jp-ui-font-color0); + font-weight: 400; + grid-area: title; + padding: 0; + margin-top: calc(var(--jp-private-settingeditor-header-spacing) * 2); + margin-bottom: calc(var(--jp-private-settingeditor-header-spacing) / 2); } -.jp-SettingsPanel .jp-modifiedIndicator { - width: 5px; - background-color: var(--jp-brand-color2); - margin-top: 0; - margin-left: calc(var(--jp-private-settingeditor-modifier-indent) * -1); - flex-shrink: 0; -} - -.jp-SettingsPanel .jp-FormGroup-fieldLabel { - font-size: var(--jp-content-font-size1); - font-weight: normal; - min-width: 120px; -} - -.jp-SettingsPanel .jp-modifiedIndicator.jp-errorIndicator { - background-color: var(--jp-error-color0); +.jp-SettingsHeader-description { + grid-area: description; + padding-bottom: var(--jp-private-settingeditor-header-spacing); + color: var(--jp-ui-font-color1); } -.jp-SettingsPanel .validationErrors { - color: var(--jp-error-color0); +.jp-SettingsHeader-buttonbar { + margin: auto var(--jp-private-settingeditor-header-spacing); + grid-row: span 2; } -.jp-SettingsPanel .panel.errors { - display: none; +.jp-SettingsHeader-buttonbar > .jp-RestoreButton { + background-color: var(--jp-warn-color-normal); + border: 0; + color: var(--jp-ui-inverse-font-color0); } -.jp-SettingsPanel .jp-SettingsEditor { - padding: 20px; +.jp-PluginEditor { + overflow: auto; } -.jp-SettingsPanel .jp-SettingEditor-Switch .jp-switch { - position: absolute; - bottom: 0; - z-index: 999; - background-color: var(--jp-border-color3); - border: 1px solid var(--jp-border-color1); -} +/** Placeholder **/ -.jp-SettingsPanel { - overflow-y: auto; - height: 100%; +.jp-SettingsEditor-placeholder { + text-align: center; } -.jp-SettingsForm button.jp-RestoreButton { - white-space: nowrap; - background: none; - border: none; - outline: none; - box-shadow: none; - font-size: var(--jp-content-font-size2); - color: var(--jp-brand-color1); - cursor: pointer; - margin-right: 5px; +.jp-SettingsEditor-placeholderContent { + color: var(--jp-content-font-color2); + padding: 8px; } -.jp-PluginEditor { - overflow: auto; +.jp-SettingsEditor-placeholderContent > h3 { + margin-bottom: var(--jp-content-heading-margin-bottom); } diff --git a/packages/settingeditor/style/index.css b/packages/settingeditor/style/index.css index c1dc0aaf298c..3ec7436a26ab 100644 --- a/packages/settingeditor/style/index.css +++ b/packages/settingeditor/style/index.css @@ -11,5 +11,4 @@ @import url('~@jupyterlab/rendermime/style/index.css'); @import url('~@jupyterlab/application/style/index.css'); @import url('~@jupyterlab/inspector/style/index.css'); - @import url('./base.css'); diff --git a/packages/settingeditor/test/settingsformeditor.spec.tsx b/packages/settingeditor/test/settingsformeditor.spec.tsx new file mode 100644 index 000000000000..124f6cf3bfcb --- /dev/null +++ b/packages/settingeditor/test/settingsformeditor.spec.tsx @@ -0,0 +1,123 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. +import { nullTranslator } from '@jupyterlab/translation'; +import { SettingsFormEditor } from '../src/SettingsFormEditor'; +import React from 'react'; +import renderer from 'react-test-renderer'; +import { StateDB } from '@jupyterlab/statedb'; +import { + ISettingRegistry, + SettingRegistry, + Settings +} from '@jupyterlab/settingregistry'; +import { FormComponent } from '@jupyterlab/ui-components'; + +class TestConnector extends StateDB { + schemas: { [key: string]: ISettingRegistry.ISchema } = {}; + + async fetch(id: string): Promise { + const fetched = await super.fetch(id); + if (!fetched && !this.schemas[id]) { + return undefined; + } + + const schema: ISettingRegistry.ISchema = this.schemas[id] || { + type: 'object' + }; + const composite = {}; + const user = {}; + const raw = (fetched as string) || '{ }'; + const version = 'test'; + return { id, data: { composite, user }, raw, schema, version }; + } + + async list(): Promise { + return Promise.reject('list method not implemented'); + } +} + +describe('@jupyterlab/settingeditor', () => { + describe('SettingFormEditor', () => { + let connector: TestConnector; + let registry: SettingRegistry; + let settings: Settings | null; + + beforeAll(() => { + connector = new TestConnector(); + }); + + beforeEach(() => { + registry = new SettingRegistry({ connector }); + }); + + afterEach(async () => { + if (settings) { + settings.dispose(); + settings = null; + } + connector.schemas = {}; + await connector.clear(); + }); + + it('should render a dummy schema', async () => { + const id = 'alpha'; + const schema: ISettingRegistry.ISchema = { type: 'object' }; + + connector.schemas[id] = schema; + + settings = (await registry.load(id)) as Settings; + + const component = renderer.create( + void 0} + onSelect={() => void 0} + renderers={{}} + settings={settings} + translator={nullTranslator} + updateDirtyState={() => void 0} + > + ); + + expect(component).not.toBeNull(); + }); + + it('should render a subset of the schema', async () => { + // If + const id = 'alpha'; + const schema: ISettingRegistry.ISchema = { + type: 'object', + properties: { + keyA: { type: 'string', default: 'A' }, + keyB: { type: 'string', default: 'B' }, + keyC: { title: 'Third key', type: 'string', default: 'C' }, + keyD: { type: 'string', default: 'D' } + } + }; + connector.schemas[id] = schema; + settings = (await registry.load(id)) as Settings; + + // When + const component = renderer.create( + void 0} + onSelect={() => void 0} + renderers={{}} + settings={settings} + translator={nullTranslator} + updateDirtyState={() => void 0} + > + ); + + // Then + const instance = component.root; + const form = instance.findByType(FormComponent); + expect(form.props.formData).toEqual({ keyA: 'A', keyC: 'C' }); + expect(Object.keys(form.props.schema.properties)).toEqual( + Object.keys(form.props.formData) + ); + }); + }); +}); diff --git a/packages/docprovider/tsconfig.test.json b/packages/settingeditor/tsconfig.test.json similarity index 52% rename from packages/docprovider/tsconfig.test.json rename to packages/settingeditor/tsconfig.test.json index 2a7b9300bb95..e35a07b2631e 100644 --- a/packages/docprovider/tsconfig.test.json +++ b/packages/settingeditor/tsconfig.test.json @@ -3,40 +3,37 @@ "include": ["src/*", "test/*"], "references": [ { - "path": "../apputils" - }, - { - "path": "../coreutils" + "path": "../application" }, { - "path": "../services" + "path": "../apputils" }, { - "path": "../shared-models" + "path": "../codeeditor" }, { - "path": "../translation" + "path": "../inspector" }, { - "path": "." + "path": "../rendermime" }, { - "path": "../../testutils" + "path": "../settingregistry" }, { - "path": "../apputils" + "path": "../statedb" }, { - "path": "../coreutils" + "path": "../translation" }, { - "path": "../services" + "path": "../ui-components" }, { - "path": "../shared-models" + "path": "." }, { - "path": "../translation" + "path": "../testing" } ] } diff --git a/packages/settingregistry/.vscode/launch.json b/packages/settingregistry/.vscode/launch.json index 3c841b4f2ce8..66fb4b825a88 100644 --- a/packages/settingregistry/.vscode/launch.json +++ b/packages/settingregistry/.vscode/launch.json @@ -12,4 +12,4 @@ "port": 9229 } ] -} \ No newline at end of file +} diff --git a/packages/settingregistry/babel.config.js b/packages/settingregistry/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/packages/settingregistry/babel.config.js +++ b/packages/settingregistry/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/packages/settingregistry/jest.config.js b/packages/settingregistry/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/settingregistry/jest.config.js +++ b/packages/settingregistry/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/settingregistry/package.json b/packages/settingregistry/package.json index 2a714167f493..bf522f0fb796 100644 --- a/packages/settingregistry/package.json +++ b/packages/settingregistry/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/settingregistry", - "version": "3.6.6", + "version": "4.0.8", "description": "Settings registry for Jupyterlab", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -21,7 +21,9 @@ "files": [ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "schema/*.json", - "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}" + "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", + "src/**/*.{ts,tsx}", + "src/plugin-schema.json" ], "scripts": { "build": "tsc -b", @@ -30,27 +32,30 @@ "docs": "typedoc src --tsconfig typedoc-tsconfig.json", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/statedb": "^3.6.6", - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/signaling": "^1.10.0", - "ajv": "^6.12.3", - "json5": "^2.1.1" + "@jupyterlab/nbformat": "^4.0.8", + "@jupyterlab/statedb": "^4.0.8", + "@lumino/commands": "^2.1.3", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/signaling": "^2.1.2", + "@rjsf/utils": "^5.1.0", + "ajv": "^8.12.0", + "json5": "^2.2.3" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "@types/json5": "^0.0.30", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "ts-jest": "^26.3.0", - "typescript": "~4.1.3" + "typescript": "~5.0.4" + }, + "peerDependencies": { + "react": ">=16" }, "publishConfig": { "access": "public" diff --git a/packages/settingregistry/src/plugin-schema.json b/packages/settingregistry/src/plugin-schema.json index 9b971cc0cdea..1ebcdf421bb7 100644 --- a/packages/settingregistry/src/plugin-schema.json +++ b/packages/settingregistry/src/plugin-schema.json @@ -56,6 +56,13 @@ }, "additionalProperties": false }, + "jupyter.lab.metadataforms": { + "items": { + "$ref": "#/definitions/metadataForm" + }, + "type": "array", + "default": [] + }, "jupyter.lab.setting-deprecated": { "type": "boolean", "default": false @@ -280,6 +287,11 @@ "description": "If defined, it will override the command label", "type": "string" }, + "caption": { + "title": "Item caption", + "description": "If defined, it will override the command caption", + "type": "string" + }, "type": { "title": "Item type", "type": "string", @@ -295,6 +307,87 @@ "required": ["name"], "additionalProperties": false, "type": "object" + }, + "metadataForm": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The section ID" + }, + "metadataSchema": { + "type": "object", + "items": { + "$ref": "#/definitions/metadataSchema" + } + }, + "uiSchema": { + "type": "object" + }, + "metadataOptions": { + "type": "object", + "items": { + "$ref": "#/definitions/metadataOptions" + } + }, + "label": { + "type": "string", + "description": "The section label" + }, + "rank": { + "type": "integer", + "description": "The rank of the section in the right panel" + }, + "showModified": { + "type": "boolean", + "description": "Whether to show modified values from defaults" + } + }, + "required": ["id", "metadataSchema"] + }, + "metadataSchema": { + "properties": { + "properties": { + "type": "object", + "description": "The property set up by extension", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + }, + "type": "object", + "required": ["properties"] + }, + "metadataOptions": { + "properties": { + "customRenderer": { + "type": "string" + }, + "metadataLevel": { + "type": "string", + "enum": ["cell", "notebook"], + "default": "cell" + }, + "cellTypes": { + "type": "array", + "items": { + "type": "string", + "enum": ["code", "markdown", "raw"] + } + }, + "writeDefault": { + "type": "boolean" + } + }, + "type": "object" } } } diff --git a/packages/settingregistry/src/settingregistry.ts b/packages/settingregistry/src/settingregistry.ts index 94a3b80cccf2..c1e71224ff6a 100644 --- a/packages/settingregistry/src/settingregistry.ts +++ b/packages/settingregistry/src/settingregistry.ts @@ -16,7 +16,7 @@ import { } from '@lumino/coreutils'; import { DisposableDelegate, IDisposable } from '@lumino/disposable'; import { ISignal, Signal } from '@lumino/signaling'; -import Ajv from 'ajv'; +import Ajv, { Options as AjvOptions } from 'ajv'; import * as json5 from 'json5'; import SCHEMA from './plugin-schema.json'; import { ISettingRegistry } from './tokens'; @@ -26,6 +26,18 @@ import { ISettingRegistry } from './tokens'; */ const copy = JSONExt.deepCopy; +/** Default arguments for Ajv instances. + * + * https://ajv.js.org/options.html + */ +const AJV_DEFAULT_OPTIONS: Partial = { + /** + * @todo the implications of enabling strict mode are beyond the scope of + * the initial PR + */ + strict: false +}; + /** * The default number of milliseconds before a `load()` call to the registry * will wait before timing out if it requires a transformation that has not been @@ -51,7 +63,7 @@ export interface ISchemaValidator { * @param populate - Whether plugin data should be populated, defaults to * `true`. * - * @return A list of errors if either the schema or data fail to validate or + * @returns A list of errors if either the schema or data fail to validate or * `null` if there are no errors. */ validateData( @@ -68,20 +80,15 @@ export namespace ISchemaValidator { * A schema validation error definition. */ export interface IError { - /** - * The path in the data where the error occurred. - */ - dataPath: string; - /** * The keyword whose validation failed. */ - keyword: string; + keyword: string | string[]; /** * The error message. */ - message: string; + message?: string; /** * Optional parameter metadata that might be included in an error. @@ -92,6 +99,31 @@ export namespace ISchemaValidator { * The path in the schema where the error occurred. */ schemaPath: string; + + /** + * @todo handle new fields from ajv8 + **/ + schema?: unknown; + + /** + * @todo handle new fields from ajv8 + **/ + instancePath: string; + + /** + * @todo handle new fields from ajv8 + **/ + propertyName?: string; + + /** + * @todo handle new fields from ajv8 + **/ + data?: unknown; + + /** + * @todo handle new fields from ajv8 + **/ + parentSchema?: unknown; } } @@ -116,7 +148,7 @@ export class DefaultSchemaValidator implements ISchemaValidator { * @param populate - Whether plugin data should be populated, defaults to * `true`. * - * @return A list of errors if either the schema or data fail to validate or + * @returns A list of errors if either the schema or data fail to validate or * `null` if there are no errors. */ validateData( @@ -134,7 +166,7 @@ export class DefaultSchemaValidator implements ISchemaValidator { `Setting registry schemas' root-level type must be ` + `'object', rejecting type: ${plugin.schema.type}`; - return [{ dataPath: 'type', keyword, schemaPath: '', message }]; + return [{ instancePath: 'type', keyword, schemaPath: '', message }]; } const errors = this._addSchema(plugin.id, plugin.schema); @@ -150,7 +182,7 @@ export class DefaultSchemaValidator implements ISchemaValidator { if (error instanceof SyntaxError) { return [ { - dataPath: '', + instancePath: '', keyword: 'syntax', schemaPath: '', message: error.message @@ -163,7 +195,7 @@ export class DefaultSchemaValidator implements ISchemaValidator { return [ { - dataPath: '', + instancePath: '', keyword: 'parse', schemaPath: '', message: `${description} (line ${line} column ${column})` @@ -196,7 +228,7 @@ export class DefaultSchemaValidator implements ISchemaValidator { * * @param schema - The schema being added. * - * @return A list of errors if the schema fails to validate or `null` if there + * @returns A list of errors if the schema fails to validate or `null` if there * are no errors. * * #### Notes @@ -231,8 +263,11 @@ export class DefaultSchemaValidator implements ISchemaValidator { return null; } - private _composer = new Ajv({ useDefaults: true }); - private _validator = new Ajv(); + private _composer: Ajv = new Ajv({ + useDefaults: true, + ...AJV_DEFAULT_OPTIONS + }); + private _validator: Ajv = new Ajv({ ...AJV_DEFAULT_OPTIONS }); } /** @@ -247,8 +282,15 @@ export class SettingRegistry implements ISettingRegistry { this.validator = options.validator || new DefaultSchemaValidator(); this._timeout = options.timeout || DEFAULT_TRANSFORM_TIMEOUT; - // Preload with any available data at instantiation-time. + // Plugins with transformation may not be loaded if the transformation function is + // not yet available. To avoid fetching again the associated data when the transformation + // function is available, the plugin data is kept in cache. if (options.plugins) { + options.plugins + .filter(plugin => plugin.schema['jupyter.lab.transform']) + .forEach(plugin => this._unloadedPlugins.set(plugin.id, plugin)); + + // Preload with any available data at instantiation-time. this._ready = this._preload(options.plugins); } } @@ -321,10 +363,15 @@ export class SettingRegistry implements ISettingRegistry { * * @param plugin - The name of the plugin whose settings are being loaded. * + * @param forceTransform - An optional parameter to force replay the transforms methods. + * * @returns A promise that resolves with a plugin settings object or rejects * if the plugin is not found. */ - async load(plugin: string): Promise { + async load( + plugin: string, + forceTransform: boolean = false + ): Promise { // Wait for data preload before allowing normal operation. await this._ready; @@ -333,9 +380,28 @@ export class SettingRegistry implements ISettingRegistry { // If the plugin exists, resolve. if (plugin in plugins) { + // Force replaying the transform function if expected. + if (forceTransform) { + // Empty the composite and user data before replaying the transforms. + plugins[plugin].data = { composite: {}, user: {} }; + await this._load(await this._transform('fetch', plugins[plugin])); + this._pluginChanged.emit(plugin); + } return new Settings({ plugin: plugins[plugin], registry }); } + // If the plugin is not loaded but has already been fetched. + if (this._unloadedPlugins.has(plugin) && plugin in this._transformers) { + await this._load( + await this._transform('fetch', this._unloadedPlugins.get(plugin)!) + ); + if (plugin in plugins) { + this._pluginChanged.emit(plugin); + this._unloadedPlugins.delete(plugin); + return new Settings({ plugin: plugins[plugin], registry }); + } + } + // If the plugin needs to be loaded from the data connector, fetch. return this.reload(plugin); } @@ -359,7 +425,7 @@ export class SettingRegistry implements ISettingRegistry { if (fetched === undefined) { throw [ { - dataPath: '', + instancePath: '', keyword: 'id', message: `Could not fetch settings for ${plugin}.`, schemaPath: '' @@ -514,10 +580,12 @@ export class SettingRegistry implements ISettingRegistry { const output = [`Validating ${plugin} failed:`]; (errors as ISchemaValidator.IError[]).forEach((error, index) => { - const { dataPath, schemaPath, keyword, message } = error; + const { instancePath, schemaPath, keyword, message } = error; - if (dataPath || schemaPath) { - output.push(`${index} - schema @ ${schemaPath}, data @ ${dataPath}`); + if (instancePath || schemaPath) { + output.push( + `${index} - schema @ ${schemaPath}, data @ ${instancePath}` + ); } output.push(`{${keyword}} ${message}`); }); @@ -569,7 +637,7 @@ export class SettingRegistry implements ISettingRegistry { if (fetched === undefined) { throw [ { - dataPath: '', + instancePath: '', keyword: 'id', message: `Could not fetch settings for ${plugin}.`, schemaPath: '' @@ -603,7 +671,7 @@ export class SettingRegistry implements ISettingRegistry { if (transformed.id !== id) { throw [ { - dataPath: '', + instancePath: '', keyword: 'id', message: 'Plugin transformations cannot change plugin IDs.', schemaPath: '' @@ -626,7 +694,7 @@ export class SettingRegistry implements ISettingRegistry { throw [ { - dataPath: '', + instancePath: '', keyword: 'timeout', message: `Transforming ${plugin.id} timed out.`, schemaPath: '' @@ -657,16 +725,74 @@ export class SettingRegistry implements ISettingRegistry { [phase in ISettingRegistry.IPlugin.Phase]: ISettingRegistry.IPlugin.Transform; }; } = Object.create(null); + private _unloadedPlugins = new Map(); +} + +/** + * Base settings specified by a JSON schema. + */ +export class BaseSettings< + T extends ISettingRegistry.IProperty = ISettingRegistry.IProperty +> { + constructor(options: { schema: T }) { + this._schema = options.schema; + } + + /** + * The plugin's schema. + */ + get schema(): T { + return this._schema; + } + + /** + * Checks if any fields are different from the default value. + */ + isDefault(user: ReadonlyPartialJSONObject): boolean { + for (const key in this.schema.properties) { + const value = user[key]; + const defaultValue = this.default(key); + if ( + value === undefined || + defaultValue === undefined || + JSONExt.deepEqual(value, JSONExt.emptyObject) || + JSONExt.deepEqual(value, JSONExt.emptyArray) + ) { + continue; + } + if (!JSONExt.deepEqual(value, defaultValue)) { + return false; + } + } + return true; + } + + /** + * Calculate the default value of a setting by iterating through the schema. + * + * @param key - The name of the setting whose default value is calculated. + * + * @returns A calculated default JSON value for a specific setting. + */ + default(key?: string): PartialJSONValue | undefined { + return Private.reifyDefault(this.schema, key); + } + + private _schema: T; } /** * A manager for a specific plugin's settings. */ -export class Settings implements ISettingRegistry.ISettings { +export class Settings + extends BaseSettings + implements ISettingRegistry.ISettings +{ /** * Instantiate a new plugin settings manager. */ constructor(options: Settings.IOptions) { + super({ schema: options.plugin.schema }); this.id = options.plugin.id; this.registry = options.registry; this.registry.pluginChanged.connect(this._onPluginChanged, this); @@ -707,13 +833,6 @@ export class Settings implements ISettingRegistry.ISettings { return this.registry.plugins[this.id]!; } - /** - * The plugin's schema. - */ - get schema(): ISettingRegistry.ISchema { - return this.plugin.schema; - } - /** * The plugin settings raw text value. */ @@ -722,27 +841,8 @@ export class Settings implements ISettingRegistry.ISettings { } /** - * Checks if any fields are different from the default value. + * Whether the settings have been modified by the user or not. */ - isDefault(user: ReadonlyPartialJSONObject): boolean { - for (const key in this.schema.properties) { - const value = user[key]; - const defaultValue = this.default(key); - if ( - value === undefined || - defaultValue === undefined || - JSONExt.deepEqual(value, JSONExt.emptyObject) || - JSONExt.deepEqual(value, JSONExt.emptyArray) - ) { - continue; - } - if (!JSONExt.deepEqual(value, defaultValue)) { - return false; - } - } - return true; - } - get isModified(): boolean { return !this.isDefault(this.user); } @@ -768,17 +868,6 @@ export class Settings implements ISettingRegistry.ISettings { return Private.annotatedDefaults(this.schema, this.id); } - /** - * Calculate the default value of a setting by iterating through the schema. - * - * @param key - The name of the setting whose default value is calculated. - * - * @returns A calculated default JSON value for a specific setting. - */ - default(key?: string): PartialJSONValue | undefined { - return Private.reifyDefault(this.schema, key); - } - /** * Dispose of the plugin settings resources. */ @@ -802,9 +891,7 @@ export class Settings implements ISettingRegistry.ISettings { * This method returns synchronously because it uses a cached copy of the * plugin settings that is synchronized with the registry. */ - get( - key: string - ): { + get(key: string): { composite: ReadonlyPartialJSONValue | undefined; user: ReadonlyPartialJSONValue | undefined; } { @@ -1096,9 +1183,8 @@ export namespace SettingRegistry { // If a user shortcut collides with another user shortcut warn and filter. user = user.filter(shortcut => { - const keys = CommandRegistry.normalizeKeys(shortcut).join( - RECORD_SEPARATOR - ); + const keys = + CommandRegistry.normalizeKeys(shortcut).join(RECORD_SEPARATOR); if (!keys) { console.warn( 'Skipping this shortcut because there are no actionable keys on this platform', @@ -1132,9 +1218,8 @@ export namespace SettingRegistry { ...defaults.filter(s => !!s.disabled), ...defaults.filter(s => !s.disabled) ].filter(shortcut => { - const keys = CommandRegistry.normalizeKeys(shortcut).join( - RECORD_SEPARATOR - ); + const keys = + CommandRegistry.normalizeKeys(shortcut).join(RECORD_SEPARATOR); if (!keys) { return false; @@ -1378,9 +1463,10 @@ namespace Private { */ export function reifyDefault( schema: ISettingRegistry.IProperty, - root?: string + root?: string, + definitions?: PartialJSONObject ): PartialJSONValue | undefined { - const definitions = schema.definitions as PartialJSONObject; + definitions = definitions ?? (schema.definitions as PartialJSONObject); // If the property is at the root level, traverse its schema. schema = (root ? schema.properties?.[root] : schema) || {}; @@ -1391,7 +1477,11 @@ namespace Private { // Iterate through and populate each child property. const props = schema.properties || {}; for (const property in props) { - result[property] = reifyDefault(props[property]); + result[property] = reifyDefault( + props[property], + undefined, + definitions + ); } return result; @@ -1412,7 +1502,9 @@ namespace Private { // Iterate through the items in the array and fill in defaults for (const item in result) { // Use the values that are hard-coded in the default array over the defaults for each field. - const reified = (reifyDefault(props) as PartialJSONObject) || {}; + const reified = + (reifyDefault(props, undefined, definitions) as PartialJSONObject) ?? + {}; for (const prop in reified) { if ((result[item] as PartialJSONObject)?.[prop]) { reified[prop] = (result[item] as PartialJSONObject)[prop]; diff --git a/packages/settingregistry/src/tokens.ts b/packages/settingregistry/src/tokens.ts index 34cc1a03f7f1..85bf8ca0e9e2 100644 --- a/packages/settingregistry/src/tokens.ts +++ b/packages/settingregistry/src/tokens.ts @@ -3,6 +3,7 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ +import { CellType } from '@jupyterlab/nbformat'; import { IDataConnector } from '@jupyterlab/statedb'; import { PartialJSONObject, @@ -14,15 +15,17 @@ import { import { IDisposable } from '@lumino/disposable'; import { ISignal } from '@lumino/signaling'; import { ISchemaValidator } from './settingregistry'; +import type { RJSFSchema, UiSchema } from '@rjsf/utils'; -/* tslint:disable */ /** * The setting registry token. */ export const ISettingRegistry = new Token( - '@jupyterlab/coreutils:ISettingRegistry' + '@jupyterlab/coreutils:ISettingRegistry', + `A service for the JupyterLab settings system. + Use this if you want to store settings for your application. + See "schemaDir" for more information.` ); -/* tslint:enable */ /** * The settings registry interface. @@ -77,10 +80,15 @@ export interface ISettingRegistry { * * @param plugin - The name of the plugin whose settings are being loaded. * + * @param forceTransform - An optional parameter to force replay the transforms methods. + * * @returns A promise that resolves with a plugin settings object or rejects * if the plugin is not found. */ - load(plugin: string): Promise; + load( + plugin: string, + forceTransform?: boolean + ): Promise; /** * Reload a plugin's settings into the registry even if they already exist. @@ -281,6 +289,9 @@ export namespace ISettingRegistry { disabled?: boolean; } + /** + * An interface describing a context menu item + */ export interface IContextMenuItem extends IMenuItem { /** * The CSS selector for the context menu item. @@ -437,6 +448,11 @@ export namespace ISettingRegistry { */ 'jupyter.lab.shortcuts'?: IShortcut[]; + /** + * The JupyterLab metadata-form schema + */ + 'jupyter.lab.metadataforms'?: IMetadataForm[]; + /** * The root schema is always an object. */ @@ -526,9 +542,7 @@ export namespace ISettingRegistry { * * @returns The setting value. */ - get( - key: string - ): { + get(key: string): { composite: ReadonlyPartialJSONValue | undefined; user: ReadonlyPartialJSONValue | undefined; }; @@ -609,6 +623,101 @@ export namespace ISettingRegistry { selector: string; } + /** + * An interface describing the metadata form. + */ + export interface IMetadataForm extends PartialJSONObject { + /** + * The section unique ID. + */ + id: string; + + /** + * The metadata schema. + */ + metadataSchema: IMetadataSchema; + + /** + * The ui schema as used by react-JSON-schema-form. + */ + uiSchema?: { [metadataKey: string]: UiSchema }; + + /** + * The jupyter properties. + */ + metadataOptions?: { [metadataKey: string]: IMetadataOptions }; + + /** + * The section label. + */ + label?: string; + + /** + * The section rank in notebooktools panel. + */ + rank?: number; + + /** + * Whether to show the modified field from default value. + */ + showModified?: boolean; + + /** + * Keep the plugin at origin of the metadata form. + */ + _origin?: string; + } + + /** + * The metadata schema as defined in JSON schema. + */ + export interface IMetadataSchema extends RJSFSchema { + /** + * The properties as defined in JSON schema, and interpretable by react-JSON-schema-form. + */ + properties: { [option: string]: any }; + + /** + * The required fields. + */ + required?: string[]; + + /** + * Support for allOf feature of JSON schema (useful for if/then/else). + */ + allOf?: Array; + } + + /** + * Options to customize the widget, the field and the relevant metadata. + */ + export interface IMetadataOptions extends PartialJSONObject { + /** + * Name of a custom react widget registered. + */ + customWidget?: string; + + /** + * Name of a custom react field registered. + */ + customField?: string; + + /** + * Metadata applied to notebook or cell. + */ + metadataLevel?: 'cell' | 'notebook'; + + /** + * Cells which should have this metadata. + */ + cellTypes?: CellType[]; + + /** + * Whether to avoid writing default value in metadata. + */ + writeDefault?: boolean; + } + /** * An interface describing a toolbar item. */ diff --git a/packages/settingregistry/test/settingregistry.spec.ts b/packages/settingregistry/test/settingregistry.spec.ts index 1663c2915233..ae09944d2bac 100644 --- a/packages/settingregistry/test/settingregistry.spec.ts +++ b/packages/settingregistry/test/settingregistry.spec.ts @@ -8,7 +8,7 @@ import { Settings } from '@jupyterlab/settingregistry'; import { StateDB } from '@jupyterlab/statedb'; -import { signalToPromise } from '@jupyterlab/testutils'; +import { signalToPromise } from '@jupyterlab/testing'; import { JSONObject } from '@lumino/coreutils'; class TestConnector extends StateDB { @@ -903,6 +903,44 @@ describe('@jupyterlab/settingregistry', () => { expect(settings.default('baz')).toEqual(defaults.baz); expect(settings.default('nonexistent-default')).toBeUndefined(); }); + + it('should use definition at top of the schema', async () => { + const id = 'omicron'; + const defaults = { + foo: [ + { bar: 2, baz: 'zip' }, + { bar: 0, baz: 'zip' } + ] + }; + + connector.schemas[id] = { + type: 'object', + properties: { + foo: { + type: 'array', + items: { $ref: '#/definitions/fooItem' }, + default: [{ bar: 2 }, {}] + } + }, + definitions: { + fooItem: { + type: 'object', + properties: { + bar: { + type: 'number', + default: 0 + }, + baz: { + type: 'string', + default: 'zip' + } + } + } + } + }; + settings = (await registry.load(id)) as Settings; + expect(settings.default()).toStrictEqual(defaults); + }); }); describe('#get()', () => { diff --git a/packages/settingregistry/tsconfig.json b/packages/settingregistry/tsconfig.json index 8a31ba357f84..b72ad7b71f52 100644 --- a/packages/settingregistry/tsconfig.json +++ b/packages/settingregistry/tsconfig.json @@ -7,6 +7,9 @@ "files": ["src/plugin-schema.json"], "include": ["src/*"], "references": [ + { + "path": "../nbformat" + }, { "path": "../statedb" } diff --git a/packages/settingregistry/tsconfig.test.json b/packages/settingregistry/tsconfig.test.json index cc7992954554..8cf8a66c6213 100644 --- a/packages/settingregistry/tsconfig.test.json +++ b/packages/settingregistry/tsconfig.test.json @@ -3,16 +3,16 @@ "include": ["src/*", "test/*"], "references": [ { - "path": "../statedb" + "path": "../nbformat" }, { - "path": "." + "path": "../statedb" }, { - "path": "../../testutils" + "path": "." }, { - "path": "../statedb" + "path": "../testing" } ] } diff --git a/packages/shared-models/babel.config.js b/packages/shared-models/babel.config.js deleted file mode 100644 index 8b5c76420c60..000000000000 --- a/packages/shared-models/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); diff --git a/packages/shared-models/jest.config.js b/packages/shared-models/jest.config.js deleted file mode 100644 index 178440a1c5f3..000000000000 --- a/packages/shared-models/jest.config.js +++ /dev/null @@ -1,2 +0,0 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); -module.exports = func(__dirname); diff --git a/packages/shared-models/package.json b/packages/shared-models/package.json deleted file mode 100644 index 190cda02c33a..000000000000 --- a/packages/shared-models/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@jupyterlab/shared-models", - "version": "3.6.6", - "description": "JupyterLab - Shared Models", - "homepage": "https://github.com/jupyterlab/jupyterlab", - "bugs": { - "url": "https://github.com/jupyterlab/jupyterlab/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/jupyterlab/jupyterlab.git" - }, - "license": "BSD-3-Clause", - "author": "Project Jupyter", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "directories": { - "lib": "lib/" - }, - "files": [ - "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}" - ], - "scripts": { - "build": "tsc -b", - "clean": "rimraf lib tsconfig.tsbuildinfo", - "docs": "typedoc src --tsconfig typedoc-tsconfig.json", - "watch": "tsc -b --watch" - }, - "dependencies": { - "@jupyter/ydoc": "~0.2.4", - "@jupyterlab/nbformat": "^3.6.6" - }, - "devDependencies": { - "rimraf": "~3.0.0", - "typescript": "~4.1.3" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/packages/shared-models/typedoc.json b/packages/shared-models/typedoc.json deleted file mode 100644 index 3853cec6df80..000000000000 --- a/packages/shared-models/typedoc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "out": "../../docs/api/shared-models", - "theme": "../../typedoc-theme" -} diff --git a/packages/shortcuts-extension/.vscode/launch.json b/packages/shortcuts-extension/.vscode/launch.json index 3c841b4f2ce8..66fb4b825a88 100644 --- a/packages/shortcuts-extension/.vscode/launch.json +++ b/packages/shortcuts-extension/.vscode/launch.json @@ -12,4 +12,4 @@ "port": 9229 } ] -} \ No newline at end of file +} diff --git a/packages/shortcuts-extension/babel.config.js b/packages/shortcuts-extension/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/packages/shortcuts-extension/babel.config.js +++ b/packages/shortcuts-extension/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/packages/shortcuts-extension/jest.config.js b/packages/shortcuts-extension/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/shortcuts-extension/jest.config.js +++ b/packages/shortcuts-extension/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/shortcuts-extension/package.json b/packages/shortcuts-extension/package.json index 7f683bc25cd3..d3ccb2e25efd 100644 --- a/packages/shortcuts-extension/package.json +++ b/packages/shortcuts-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/shortcuts-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Shortcuts Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -26,7 +26,8 @@ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", "style/index.js", - "schema/*.json" + "schema/*.json", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -35,33 +36,30 @@ "docs": "typedoc src", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/domutils": "^1.8.0", - "@lumino/keyboard": "^1.8.1", - "@lumino/widgets": "^1.37.2", - "react": "^17.0.1", - "typestyle": "^2.0.4" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/algorithm": "^2.0.1", + "@lumino/commands": "^2.1.3", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/domutils": "^2.0.1", + "@lumino/keyboard": "^2.0.1", + "@lumino/widgets": "^2.3.0", + "react": "^18.2.0" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", "rimraf": "~3.0.0", - "ts-jest": "^26.3.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/shortcuts-extension/src/components/ShortcutInput.tsx b/packages/shortcuts-extension/src/components/ShortcutInput.tsx index 6a3871ef09f1..62cd1b3f2b90 100644 --- a/packages/shortcuts-extension/src/components/ShortcutInput.tsx +++ b/packages/shortcuts-extension/src/components/ShortcutInput.tsx @@ -1,23 +1,14 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import * as React from 'react'; -import { classes } from 'typestyle'; +import { ITranslator } from '@jupyterlab/translation'; import { EN_US } from '@lumino/keyboard'; - -import { - InputBoxHiddenStyle, - InputBoxNewStyle, - InputBoxStyle, - InputSelectedTextStyle, - InputStyle, - InputTextStyle, - InputUnavailableStyle, - InputWaitingStyle, - SubmitConflictStyle, - SubmitNonFunctionalStyle, - SubmitStyle -} from '../componentStyle/ShortcutInputStyle'; -import { ITranslator } from '@jupyterlab/translation'; +import { checkIcon, errorIcon } from '@jupyterlab/ui-components'; export interface IShortcutInputProps { handleUpdate: Function; @@ -305,9 +296,10 @@ export class ShortcutInput extends React.Component< binding !== '' ) { isAvailable = false; - takenByObject = this.props.keyBindingsUsed[ - binding + '_' + this.props.shortcut.selector - ]; + takenByObject = + this.props.keyBindingsUsed[ + binding + '_' + this.props.shortcut.selector + ]; break; } } @@ -321,16 +313,18 @@ export class ShortcutInput extends React.Component< currentChain !== '' ) { isAvailable = false; - takenByObject = this.props.keyBindingsUsed[ - currentChain + '_' + this.props.shortcut.selector - ]; + takenByObject = + this.props.keyBindingsUsed[ + currentChain + '_' + this.props.shortcut.selector + ]; } /** If unavailable set takenByObject */ } else { - takenByObject = this.props.keyBindingsUsed[ - keys.join(' ') + currentChain + '_' + this.props.shortcut.selector - ]; + takenByObject = + this.props.keyBindingsUsed[ + keys.join(' ') + currentChain + '_' + this.props.shortcut.selector + ]; } /** allow to set shortcut to what it initially was if replacing */ @@ -416,18 +410,18 @@ export class ShortcutInput extends React.Component< render() { const trans = this.props.translator.load('jupyterlab'); - let inputClassName = InputStyle; + let inputClassName = 'jp-Shortcuts-Input'; if (!this.state.isAvailable) { - inputClassName = classes(inputClassName, InputUnavailableStyle); + inputClassName += ' jp-mod-unavailable-Input'; } return (
    this.handleBlur(event)} > @@ -441,10 +435,10 @@ export class ShortcutInput extends React.Component<

    {this.state.value === '' @@ -455,10 +449,10 @@ export class ShortcutInput extends React.Component< {!this.state.isAvailable && (

    ; + return ( +
    {this.props.shortcut.category}
    + ); } getLabelCell(): JSX.Element { return ( -
    +
    {this.props.shortcut.label}
    ); @@ -275,7 +254,7 @@ export class ShortcutItem extends React.Component< const trans = this.props.external.translator.load('jupyterlab'); return ( this.props.resetShortcut(this.props.shortcut)} > {trans.__('Reset')} @@ -285,29 +264,34 @@ export class ShortcutItem extends React.Component< getSourceCell(): JSX.Element { return ( -
    -
    {this.props.shortcut.source}
    +
    +
    + {this.props.shortcut.source} +
    {this.props.shortcut.source === 'Custom' && this.getResetShortCutLink()}
    ); } - getOptionalSelectorCell(): JSX.Element { + getOptionalSelectorCell(): JSX.Element | null { return this.props.showSelectors ? ( -
    +
    {this.props.shortcut.selector}
    - ) : ( -
    - ); + ) : null; } getClassNameForShortCuts(nonEmptyKeys: string[]): string { - return nonEmptyKeys.length === 0 - ? classes(ShortcutCellStyle, EmptyShortcutCellStyle) - : nonEmptyKeys.length === 1 - ? classes(ShortcutCellStyle, SingleShortcutCellStyle) - : ShortcutCellStyle; + const classes = ['jp-Shortcuts-ShortcutCell']; + switch (nonEmptyKeys.length) { + case 1: + classes.push('jp-Shortcuts-SingleCell'); + break; + case 0: + classes.push('jp-Shortcuts-EmptyCell'); + break; + } + return classes.join(' '); } getToggleInputReplaceMethod(location: ShortCutLocation): () => void { @@ -334,8 +318,8 @@ export class ShortcutItem extends React.Component<
    ( -
    -
    +
    +
    {this.toSymbols(keyBinding)}
    {index + 1 < this.props.shortcut.keys[key].length ? ( -
    ,
    +
    ,
    ) : null}
    ) @@ -406,7 +390,7 @@ export class ShortcutItem extends React.Component< const location = this.getLocationFromIndex(index); return (
    @@ -423,7 +407,7 @@ export class ShortcutItem extends React.Component< const trans = this.props.external.translator.load('jupyterlab'); return ( { this.toggleInputNew(), this.props.clearConflicts(); }} @@ -458,7 +442,7 @@ export class ShortcutItem extends React.Component< getShortCutsCell(nonEmptyKeys: string[]): JSX.Element { return ( -
    +
    {nonEmptyKeys.map((key, index) => this.getDivForKey(index, key, nonEmptyKeys) @@ -485,7 +469,7 @@ export class ShortcutItem extends React.Component< } else { return (
    { e.persist(); this.handleRightClick(e); diff --git a/packages/shortcuts-extension/src/components/ShortcutList.tsx b/packages/shortcuts-extension/src/components/ShortcutList.tsx index 3f2c8bcf2d95..cd6c60dec50c 100644 --- a/packages/shortcuts-extension/src/components/ShortcutList.tsx +++ b/packages/shortcuts-extension/src/components/ShortcutList.tsx @@ -1,11 +1,11 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import * as React from 'react'; -import { - ShortcutListContainerStyle, - ShortcutListStyle -} from '../componentStyle/ShortcutListStyle'; import { ShortcutObject, TakenByObject } from './ShortcutInput'; import { ShortcutItem } from './ShortcutItem'; -import { UISize } from './ShortcutUI'; import { IShortcutUIexternal } from './TopNav'; const TOPNAV_HEIGHT: number = 115; @@ -21,7 +21,6 @@ export interface IShortcutListProps { sortConflict: Function; clearConflicts: Function; height: number; - errorSize: UISize; contextMenu: Function; external: IShortcutUIexternal; } @@ -31,10 +30,13 @@ export class ShortcutList extends React.Component { render(): JSX.Element { return (
    -
    +
    {this.props.shortcuts.map((shortcut: ShortcutObject) => { return ( { keyBindingsUsed={this.props.keyBindingsUsed} sortConflict={this.props.sortConflict} clearConflicts={this.props.clearConflicts} - errorSize={this.props.errorSize} contextMenu={this.props.contextMenu} external={this.props.external} /> diff --git a/packages/shortcuts-extension/src/components/ShortcutTitleItem.tsx b/packages/shortcuts-extension/src/components/ShortcutTitleItem.tsx index fa39db24ee9a..cdba4694f7c2 100644 --- a/packages/shortcuts-extension/src/components/ShortcutTitleItem.tsx +++ b/packages/shortcuts-extension/src/components/ShortcutTitleItem.tsx @@ -1,12 +1,10 @@ -import * as React from 'react'; - -import { classes } from 'typestyle'; +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ -import { - CurrentHeaderStyle, - HeaderStyle, - SortButtonStyle -} from '../componentStyle/ShortcutTitleItemStyle'; +import { caretDownEmptyThinIcon } from '@jupyterlab/ui-components'; +import * as React from 'react'; export interface IShortcutTitleItemProps { title: string; @@ -14,23 +12,21 @@ export interface IShortcutTitleItemProps { active: string; } -export class ShortcutTitleItem extends React.Component< - IShortcutTitleItemProps -> { +export class ShortcutTitleItem extends React.Component { render(): JSX.Element { return (
    this.props.updateSort(this.props.title.toLowerCase())} > {this.props.title} -
    - ⌃ -
    +
    ); } diff --git a/packages/shortcuts-extension/src/components/ShortcutUI.tsx b/packages/shortcuts-extension/src/components/ShortcutUI.tsx index d702c9ea8828..eed2bde20046 100644 --- a/packages/shortcuts-extension/src/components/ShortcutUI.tsx +++ b/packages/shortcuts-extension/src/components/ShortcutUI.tsx @@ -1,14 +1,14 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { ArrayExt, StringExt } from '@lumino/algorithm'; import { ReadonlyJSONArray } from '@lumino/coreutils'; -import { - ShortcutUIStyle, - TopWhitespaceStyle -} from '../componentStyle/ShortcutUIStyle'; - import { ShortcutList } from './ShortcutList'; import { IShortcutUIexternal, TopNav } from './TopNav'; @@ -23,12 +23,6 @@ const enum MatchType { Default } -export const enum UISize { - Regular, - Small, - Tiny -} - /** Props for ShortcutUI component */ export interface IShortcutUIProps { external: IShortcutUIexternal; @@ -151,7 +145,7 @@ function matchItems(items: any, query: string): any { query = normalizeQuery(query); // Create the array to hold the scores. - let scores: Object[] = []; + let scores: any[] = []; // Iterate over the items and match against the query. let itemList = Object.keys(items); for (let i = 0, n = itemList.length; i < n; ++i) { @@ -257,7 +251,7 @@ export class ShortcutUI extends React.Component< IShortcutUIProps, IShortcutUIState > { - constructor(props: any) { + constructor(props: IShortcutUIProps) { super(props); this.state = { shortcutList: {}, @@ -277,7 +271,8 @@ export class ShortcutUI extends React.Component< } /** Fetch shortcut list from SettingRegistry */ private async _refreshShortcutList(): Promise { - const shortcuts: ISettingRegistry.ISettings = await this.props.external.getAllShortCutSettings(); + const shortcuts: ISettingRegistry.ISettings = + await this.props.external.getAllShortCutSettings(); const shortcutObjects = getShortcutObjects(this.props.external, shortcuts); this.setState( { @@ -314,7 +309,7 @@ export class ShortcutUI extends React.Component< }; /** Filter shortcut list using current search query */ - private searchFilterShortcuts(shortcutObjects: Object): ShortcutObject[] { + private searchFilterShortcuts(shortcutObjects: any): ShortcutObject[] { const filteredShortcuts = matchItems( shortcutObjects, this.state.searchQuery @@ -325,7 +320,7 @@ export class ShortcutUI extends React.Component< } /** Reset all shortcuts to their defaults */ - resetShortcuts = async () => { + resetShortcuts = async (): Promise => { const settings = await this.props.external.getAllShortCutSettings(); for (const key of Object.keys(settings.user)) { await this.props.external.removeShortCut(key); @@ -334,8 +329,12 @@ export class ShortcutUI extends React.Component< }; /** Set new shortcut for command, refresh state */ - handleUpdate = async (shortcutObject: ShortcutObject, keys: string[]) => { - const settings: ISettingRegistry.ISettings = await this.props.external.getAllShortCutSettings(); + handleUpdate = async ( + shortcutObject: ShortcutObject, + keys: string[] + ): Promise => { + const settings: ISettingRegistry.ISettings = + await this.props.external.getAllShortCutSettings(); const userShortcuts = settings.user.shortcuts as ReadonlyJSONArray; const newUserShortcuts = []; let found = false; @@ -369,14 +368,15 @@ export class ShortcutUI extends React.Component< deleteShortcut = async ( shortcutObject: ShortcutObject, shortcutId: string - ) => { + ): Promise => { await this.handleUpdate(shortcutObject, ['']); await this._refreshShortcutList(); }; /** Reset a specific shortcut to its default settings */ - resetShortcut = async (shortcutObject: ShortcutObject) => { - const settings: ISettingRegistry.ISettings = await this.props.external.getAllShortCutSettings(); + resetShortcut = async (shortcutObject: ShortcutObject): Promise => { + const settings: ISettingRegistry.ISettings = + await this.props.external.getAllShortCutSettings(); const userShortcuts = settings.user.shortcuts as ReadonlyJSONArray; const newUserShortcuts = []; for (let shortcut of userShortcuts as any) { @@ -461,7 +461,7 @@ export class ShortcutUI extends React.Component< this.setState({ filteredShortcutList: shortcutList }); }; - contextMenu = (event: any, commandIDs: string[]) => { + contextMenu = (event: React.MouseEvent, commandIDs: string[]): void => { event.persist(); this.setState( { @@ -477,13 +477,12 @@ export class ShortcutUI extends React.Component< ); }; - render() { + render(): JSX.Element | null { if (!this.state.shortcutsFetched) { return null; } return ( -
    -
    +
    diff --git a/packages/shortcuts-extension/src/components/TopNav.tsx b/packages/shortcuts-extension/src/components/TopNav.tsx index f857b98f81ba..44c80f468d80 100644 --- a/packages/shortcuts-extension/src/components/TopNav.tsx +++ b/packages/shortcuts-extension/src/components/TopNav.tsx @@ -1,34 +1,19 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { ITranslator } from '@jupyterlab/translation'; +import { InputGroup } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { IDisposable } from '@lumino/disposable'; import { Menu } from '@lumino/widgets'; import * as React from 'react'; -import { classes } from 'typestyle'; -import { CellStyle } from '../componentStyle/ShortcutItemStyle'; -import { - AdvancedOptionsContainerStyle, - AdvancedOptionsLinkStyle, - AdvancedOptionsSmallStyle, - AdvancedOptionsStyle, - altIconStyle, - commandIconStyle, - controlIconStyle, - HeaderRowContainerStyle, - HeaderRowStyle, - SearchContainerStyle, - SearchStyle, - SymbolsRowStyle, - SymbolsSmallStyle, - SymbolsStyle, - TopNavStyle, - TopStyle -} from '../componentStyle/TopNavStyle'; + import { ShortcutTitleItem } from './ShortcutTitleItem'; -import { UISize } from './ShortcutUI'; export interface IAdvancedOptionsProps { - size: UISize; toggleSelectors: Function; showSelectors: boolean; resetShortcuts: Function; @@ -36,9 +21,7 @@ export interface IAdvancedOptionsProps { translator: ITranslator; } -export interface ISymbolsProps { - size: UISize; -} +export interface ISymbolsProps {} /** All external actions, setting commands, getting command list ... */ export interface IShortcutUIexternal { @@ -59,121 +42,57 @@ export namespace CommandIDs { export const resetAll = 'shortcutui:resetAll'; } -class Symbols extends React.Component { - getRegularSymbols() { - return ( -
    -
    -
    Cmd ⌘
    -
    Alt âŒĨ
    -
    Ctrl ⌃
    -
    Shift ⇧
    -
    -
    - ); - } - - getSmallSymbols() { - return ( -
    -
    - Cmd - ⌘ - Alt - âŒĨ -
    -
    - Ctrl - ⌃ - Shift - ⇧ -
    -
    - ); - } - - getTinySymbols() { - return ( -
    -
    - Cmd - ⌘ -
    -
    - Alt - âŒĨ -
    -
    - Ctrl - ⌃ -
    -
    - Shift - ⇧ -
    -
    - ); - } - - render() { - switch (this.props.size) { - case UISize.Regular: - return this.getRegularSymbols(); - case UISize.Small: - return this.getSmallSymbols(); - case UISize.Tiny: - return this.getTinySymbols(); - } - } +function Symbols(props: ISymbolsProps): JSX.Element { + return ( +
    + + + + + + + + + + + + + + + +
    + Cmd + ⌘ + Ctrl + ⌃
    + Alt + âŒĨ + Shift + ⇧
    +
    + ); } -class AdvancedOptions extends React.Component { - render() { - const trans = this.props.translator.load('jupyterlab'); - if (this.props.size === UISize.Regular) { - return ( -
    - ); - } else { - return ( - - ); - } - } +function AdvancedOptions(props: IAdvancedOptionsProps): JSX.Element { + const trans = props.translator.load('jupyterlab'); + return ( + + ); } /** State for TopNav component */ @@ -223,19 +142,9 @@ export class TopNav extends React.Component { } } - getSize = (width: number): UISize => { - if (width < 730) { - return UISize.Tiny; - } else if (width < 1260) { - return UISize.Small; - } else { - return UISize.Regular; - } - }; - getShortCutTitleItem(title: string) { return ( -
    +
    { render() { const trans = this.props.external.translator.load('jupyterlab'); return ( -
    -
    - -
    - this.props.updateSearchQuery(event)} - className={SearchStyle} - placeholder={trans.__('Search')} - /> -
    +
    +
    + + this.props.updateSearchQuery(event)} + placeholder={trans.__('Searchâ€Ļ')} + rightIcon="ui-components:search" + /> { translator={this.props.external.translator} />
    -
    -
    +
    +
    {this.getShortCutTitleItem(trans.__('Category'))} {this.getShortCutTitleItem(trans.__('Command'))} -
    +
    {trans.__('Shortcut')}
    {this.getShortCutTitleItem(trans.__('Source'))} diff --git a/packages/shortcuts-extension/src/components/index.ts b/packages/shortcuts-extension/src/components/index.ts index e03b90e9378b..394773674095 100644 --- a/packages/shortcuts-extension/src/components/index.ts +++ b/packages/shortcuts-extension/src/components/index.ts @@ -1,2 +1,7 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + export * from './ShortcutUI'; export { IShortcutUIexternal } from './TopNav'; diff --git a/packages/shortcuts-extension/src/index.ts b/packages/shortcuts-extension/src/index.ts index 14b9f7829386..12a5acda95c0 100644 --- a/packages/shortcuts-extension/src/index.ts +++ b/packages/shortcuts-extension/src/index.ts @@ -11,7 +11,10 @@ import { } from '@jupyterlab/application'; import { ISettingRegistry, SettingRegistry } from '@jupyterlab/settingregistry'; import { ITranslator, nullTranslator } from '@jupyterlab/translation'; -import { IFormComponentRegistry } from '@jupyterlab/ui-components'; +import { + IFormRenderer, + IFormRendererRegistry +} from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { JSONExt, @@ -34,7 +37,7 @@ function getExternalForJupyterLab( return { translator, getAllShortCutSettings: () => - settingRegistry.reload(shortcutPluginLocation), + settingRegistry.load(shortcutPluginLocation, true), removeShortCut: (key: string) => settingRegistry.remove(shortcutPluginLocation, key), createMenu: () => new Menu({ commands }), @@ -76,13 +79,14 @@ function getExternalForJupyterLab( */ const shortcuts: JupyterFrontEndPlugin = { id: '@jupyterlab/shortcuts-extension:shortcuts', + description: 'Adds the keyboard shortcuts editor.', requires: [ISettingRegistry], - optional: [ITranslator, IFormComponentRegistry], + optional: [ITranslator, IFormRendererRegistry], activate: async ( app: JupyterFrontEnd, registry: ISettingRegistry, translator: ITranslator | null, - editorRegistry: IFormComponentRegistry | null + editorRegistry: IFormRendererRegistry | null ) => { const translator_ = translator ?? nullTranslator; const trans = translator_.load('jupyterlab'); @@ -91,12 +95,15 @@ const shortcuts: JupyterFrontEndPlugin = { let loaded: { [name: string]: ISettingRegistry.IShortcut[] } = {}; if (editorRegistry) { - editorRegistry.addRenderer('shortcuts', (props: any) => { - return renderShortCut({ - external: getExternalForJupyterLab(registry, app, translator_), - ...props - }); - }); + const component: IFormRenderer = { + fieldRenderer: (props: any) => { + return renderShortCut({ + external: getExternalForJupyterLab(registry, app, translator_), + ...props + }); + } + }; + editorRegistry.addRenderer(`${shortcuts.id}.shortcuts`, component); } /** @@ -164,8 +171,13 @@ List of keyboard shortcuts:`, oldShortcuts === undefined || !JSONExt.deepEqual(oldShortcuts, newShortcuts) ) { + // Empty the default values to avoid shortcut collisions. canonical = null; - await registry.reload(shortcuts.id); + const schema = registry.plugins[shortcuts.id]!.schema; + schema.properties!.shortcuts.default = []; + + // Reload the settings. + await registry.load(shortcuts.id, true); } } }); diff --git a/packages/shortcuts-extension/src/renderer.tsx b/packages/shortcuts-extension/src/renderer.tsx index f4449c77fd30..20788f063f38 100644 --- a/packages/shortcuts-extension/src/renderer.tsx +++ b/packages/shortcuts-extension/src/renderer.tsx @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import React from 'react'; import { IShortcutUIexternal, ShortcutUI } from './components'; diff --git a/packages/shortcuts-extension/style/base.css b/packages/shortcuts-extension/style/base.css new file mode 100644 index 000000000000..f0866e135a15 --- /dev/null +++ b/packages/shortcuts-extension/style/base.css @@ -0,0 +1,393 @@ +/*----------------------------------------------------------------------------- +| Copyright (c) Jupyter Development Team. +| Distributed under the terms of the Modified BSD License. +|----------------------------------------------------------------------------*/ + +/* Shortcut Input Style */ + +.jp-Shortcuts-InputBox { + display: inline-flex; + padding-top: 2px; +} + +.jp-Shortcuts-InputBoxNew { + margin-left: 10px; +} + +.jp-mod-hidden { + display: none; +} + +@keyframes slide-animation { + from { + width: 0; + left: 0; + } + + to { + width: 120px; + left: 0; + } +} + +.jp-Shortcuts-Input { + animation-duration: 0.5s; + animation-timing-function: ease-out; + animation-name: slide-animation; + border-width: var(--jp-border-width); + border-color: var(--jp-border-color3); + border-style: solid; + background-color: var(--jp-layout-color0); + margin-left: auto; + padding-left: 10px; + width: 120px; + height: 25px; + line-height: 25px; + display: block; +} + +.jp-Shortcuts-Input:focus { + outline: none; + color: var(--jp-content-font-color1); + border-color: var(--jp-brand-color2); +} + +.jp-mod-unavailable-Input:focus { + border-color: var(--jp-error-color2); +} + +.jp-Shortcuts-InputText { + overflow-x: hidden; + overflow-y: hidden; + margin: 0; + margin-top: 4px; + padding: 0 5px; + height: 17px; + line-height: 17px; + width: fit-content; +} + +.jp-mod-selected-InputText { + background-color: var(--jp-brand-color3); + overflow: hidden; +} + +.jp-mod-waiting-InputText { + color: var(--jp-content-font-color3); +} + +.jp-Shortcuts-Submit { + background-color: var(--jp-brand-color2); + border-radius: 0; + border: none; + color: var(--jp-layout-color0); + font-family: var(--jp-ui-font-family); + display: block; + height: 27px; + width: 26px; + cursor: pointer; +} + +.jp-Shortcuts-Submit:focus { + outline: none; +} + +.jp-Shortcuts-Submit .jp-icon3[fill] { + fill: var(--jp-layout-color1); +} + +.jp-Shortcuts-Submit.jp-mod-defunc-Submit { + background-color: var(--jp-layout-color3); +} + +.jp-Shortcuts-Submit.jp-mod-defunc-Submit .jp-icon3[fill] { + fill: var(--jp-inverse-layout-color1); +} + +.jp-Shortcuts-Submit.jp-mod-conflict-Submit { + background-color: var(--jp-error-color1); +} + +/* Shortcut Item Style */ +.jp-Shortcuts-Cell { + padding: 6px 12px; + display: table-cell; + width: 20%; + vertical-align: middle; +} + +.jp-Shortcuts-ShortcutCell { + display: flex; + min-width: 100px; + flex-wrap: wrap; +} + +.jp-Shortcuts-EmptyCell { + height: 32px; +} + +.jp-Shortcuts-Row { + padding: 10px; + width: 100%; + display: table-row; + border-bottom: var(--jp-border-width) solid var(--jp-border-color1); + vertical-align: middle; + background-color: var(--jp-layout-color0); +} + +.jp-Shortcuts-Row:hover .jp-Shortcuts-ShortcutKeys { + border-color: var(--jp-border-color1); + background: var(--jp-layout-color2); +} + +.jp-Shortcuts-Row:hover #add-link, +.jp-Shortcuts-Row:hover #or { + display: block; +} + +.jp-Shortcuts-ErrorMessage { + color: var(--jp-error-color1); + margin-top: 9px; +} + +.jp-Shortcuts-ErrorButton { + line-height: 34px; + margin-left: 10px; +} + +.jp-Shortcuts-ErrorButton button:nth-of-type(1) { + height: 25px; + margin-right: 5px; + background-color: var(--jp-border-color0); + color: white; + outline: none; +} + +.jp-Shortcuts-ErrorButton button:nth-of-type(1):active, +.jp-Shortcuts-ErrorButton button:nth-of-type(1):focus { + outline: none; + border: none; +} + +.jp-Shortcuts-ErrorButton button:nth-of-type(2) { + height: 25px; + background-color: var(--jp-error-color1); + color: white; + outline: none; +} + +.jp-Shortcuts-ErrorButton button:nth-of-type(2):active, +.jp-Shortcuts-ErrorButton button:nth-of-type(2):focus { + outline: none; + border: none; +} + +.jp-Shortcuts-ShortcutContainer { + display: flex; + flex-wrap: wrap; +} + +.jp-Shortcuts-ShortcutContainer:hover .jp-Shortcuts-ShortcutKeys { + border-color: var(--jp-border-color3); + background: var(--jp-layout-color3); +} + +.jp-Shortcuts-ShortcutKeysContainer { + font-size: var(--jp-code-font-size); + font-family: var(--jp-ui-font-family); + display: flex; +} + +.jp-Shortcuts-ConflictContainer { + display: flex; + flex-wrap: wrap; + padding: 6px 12px; + margin-left: 20%; +} + +.jp-Shortcuts-ShortcutKeys { + border-width: var(--jp-border-width); + border-color: var(--jp-layout-color0); + border-radius: var(--jp-border-radius); + padding: 5px 6px; + margin: 3px 0; +} + +.jp-Shortcuts-Or { + margin-right: 12px; + margin-left: 12px; + margin-top: 8px; + color: var(--jp-content-font-color3); + display: none; +} + +.jp-Shortcuts-Or:hover { + display: block; +} + +.jp-Shortcuts-OrTwo { + margin-right: 12px; + margin-left: 12px; + margin-top: 8px; + color: var(--jp-content-font-color3); + display: block; +} + +.jp-Shortcuts-Comma { + margin-top: 10px; + margin-right: 2px; + margin-left: 2px; +} + +.jp-Shortcuts-Plus { + display: none; + background: var(--jp-brand-color3); + border-color: var(--jp-layout-color0); + border-radius: var(--jp-border-radius); + border-width: var(--jp-border-width); + margin: 3px 0; + padding: 5px 6px; +} + +.jp-Shortcuts-Plus:hover { + background-color: var(--jp-brand-color2); +} + +.jp-Shortcuts-Plus:active { + background-color: var(--jp-brand-color2); +} + +.jp-Shortcuts-Reset { + color: var(--jp-brand-color2); + padding-left: 10px; +} + +.jp-Shortcuts-Reset:hover { + color: var(--jp-brand-color1); +} + +.jp-Shortcuts-SourceCell { + display: inline-block; +} + +/* Shortcut List Style */ +.jp-Shortcuts-ShortcutList { + width: 100%; + display: table; + border-collapse: collapse; +} + +.jp-Shortcuts-ShortcutListContainer { + overflow-y: scroll; + border: var(--jp-border-width) solid var(--jp-border-color1); +} + +/* Shortcut Title Item Style */ +.jp-Shortcuts-Header { + display: flex; + cursor: pointer; +} + +.jp-Shortcuts-Header:hover .jp-ShortcutTitleItem-sortButton .jp-icon3[fill], +.jp-Shortcuts-Header:focus .jp-ShortcutTitleItem-sortButton .jp-icon3[fill] { + fill: var(--jp-ui-font-color0); +} + +.jp-Shortcuts-Header:active .jp-ShortcutTitleItem-sortButton { + outline: none; +} + +.jp-Shortcuts-CurrentHeader .jp-icon3[fill] { + fill: var(--jp-ui-font-color0); +} + +/* Shortcut UI Style */ + +.jp-Shortcuts-ShortcutUI { + display: flex; + flex-direction: column; + font-size: var(--jp-ui-font-size1); + font-family: var(--jp-ui-font-family); + color: var(--jp-content-font-color1); + min-width: 450px; + width: 100%; +} + +/* TopNav Style */ +.jp-Shortcuts-Top { + display: block; +} + +.jp-Shortcuts-TopNav { + display: flex; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + font-size: var(--jp-ui-font-size1); + background-color: var(--jp-layout-color0); +} + +.jp-Shortcuts-Symbols { + padding: 0 12px; +} + +.jp-Shortcuts-Symbols td:nth-child(2) { + padding-right: 10px; +} + +.jp-Shortcuts-Search { + height: 30px; +} + +.jp-Shortcuts-Search > input { + box-shadow: none; +} + +.jp-Shortcuts-AdvancedOptionsSmall { + width: 30%; +} + +.jp-Shortcuts-AdvancedOptionsRight { + margin-top: 8px; +} + +.jp-Shortcuts-AdvancedOptionsLink { + color: var(--jp-content-link-color); + text-decoration: none; + margin-right: 15px; +} + +.jp-Shortcuts-AdvancedOptionsLink:hover { + color: var(--jp-brand-color0); +} + +.jp-Shortcuts-AdvancedOptionsLink:active { + color: var(--jp-brand-color0); +} + +.jp-Shortcuts-HeaderRowContainer { + padding-right: 14px; +} + +.jp-Shortcuts-HeaderRow { + font-weight: bold; + font-size: var(--jp-ui-font-size1); + background-color: var(--jp-layout-color0); + width: 100%; + z-index: 1; + display: table; + padding: 10px 0; +} + +.jp-Shortcuts-commandIcon { + margin-right: 13px; +} + +.jp-Shortcuts-altIcon { + margin-right: 14px; +} + +.jp-Shortcuts-controlIcon { + margin-left: 8px; + margin-right: 16px; +} diff --git a/packages/shortcuts-extension/style/index.css b/packages/shortcuts-extension/style/index.css index 70579c095a5f..f2a875036f3f 100644 --- a/packages/shortcuts-extension/style/index.css +++ b/packages/shortcuts-extension/style/index.css @@ -6,3 +6,4 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ @import url('~@lumino/widgets/style/index.css'); @import url('~@jupyterlab/ui-components/style/index.css'); +@import url('./base.css'); diff --git a/packages/shortcuts-extension/style/index.js b/packages/shortcuts-extension/style/index.js index ed162384cdde..d7ce681a90b2 100644 --- a/packages/shortcuts-extension/style/index.js +++ b/packages/shortcuts-extension/style/index.js @@ -6,3 +6,5 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ import '@lumino/widgets/style/index.js'; import '@jupyterlab/ui-components/style/index.js'; + +import './base.css'; diff --git a/packages/shortcuts-extension/test/shortcuts.spec.ts b/packages/shortcuts-extension/test/shortcuts.spec.ts index ad0ab8725070..cf0a4afc5caf 100644 --- a/packages/shortcuts-extension/test/shortcuts.spec.ts +++ b/packages/shortcuts-extension/test/shortcuts.spec.ts @@ -81,13 +81,11 @@ describe('@jupyterlab/shortcut-extension', () => { await settingRegistry.load(bar.id); - await Promise.resolve( - plugin.default.activate( - { - commands: new CommandRegistry() - } as any, - settingRegistry - ) + void plugin.default.activate( + { + commands: new CommandRegistry() + } as any, + settingRegistry ); const settings = await settingRegistry.load(plugin.default.id); @@ -151,13 +149,11 @@ describe('@jupyterlab/shortcut-extension', () => { await settingRegistry.load(bar.id); - await Promise.resolve( - plugin.default.activate( - { - commands: new CommandRegistry() - } as any, - settingRegistry - ) + void plugin.default.activate( + { + commands: new CommandRegistry() + } as any, + settingRegistry ); const settings = await settingRegistry.load(plugin.default.id); diff --git a/packages/shortcuts-extension/tsconfig.test.json b/packages/shortcuts-extension/tsconfig.test.json index 967a53a1d6df..abe0a93be526 100644 --- a/packages/shortcuts-extension/tsconfig.test.json +++ b/packages/shortcuts-extension/tsconfig.test.json @@ -18,19 +18,7 @@ "path": "." }, { - "path": "../../testutils" - }, - { - "path": "../application" - }, - { - "path": "../settingregistry" - }, - { - "path": "../translation" - }, - { - "path": "../ui-components" + "path": "../testing" } ] } diff --git a/packages/statedb/.vscode/launch.json b/packages/statedb/.vscode/launch.json index 3c841b4f2ce8..66fb4b825a88 100644 --- a/packages/statedb/.vscode/launch.json +++ b/packages/statedb/.vscode/launch.json @@ -12,4 +12,4 @@ "port": 9229 } ] -} \ No newline at end of file +} diff --git a/packages/statedb/babel.config.js b/packages/statedb/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/packages/statedb/babel.config.js +++ b/packages/statedb/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/packages/statedb/jest.config.js b/packages/statedb/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/statedb/jest.config.js +++ b/packages/statedb/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/statedb/package.json b/packages/statedb/package.json index 20b2ac851870..4032c4b8f6e1 100644 --- a/packages/statedb/package.json +++ b/packages/statedb/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/statedb", - "version": "3.6.6", + "version": "4.0.8", "description": "Package for managing state in Jupyterlab", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -21,7 +21,8 @@ "files": [ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "schema/*.json", - "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}" + "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -30,25 +31,24 @@ "docs": "typedoc src", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/properties": "^1.8.0", - "@lumino/signaling": "^1.10.0" + "@lumino/commands": "^2.1.3", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/properties": "^2.0.1", + "@lumino/signaling": "^2.1.2" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "ts-jest": "^26.3.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/statedb/src/dataconnector.ts b/packages/statedb/src/dataconnector.ts index b9fa091622aa..d93c6259fbd0 100644 --- a/packages/statedb/src/dataconnector.ts +++ b/packages/statedb/src/dataconnector.ts @@ -26,7 +26,8 @@ import { IDataConnector } from './interfaces'; * class is a convenience superclass for connectors that only need to `fetch`. */ export abstract class DataConnector - implements IDataConnector { + implements IDataConnector +{ /** * Retrieve an item from the data connector. * diff --git a/packages/statedb/src/restorablepool.ts b/packages/statedb/src/restorablepool.ts index ab4bda8fe167..1470369d9f44 100644 --- a/packages/statedb/src/restorablepool.ts +++ b/packages/statedb/src/restorablepool.ts @@ -13,8 +13,10 @@ import { IObjectPool, IRestorable } from './interfaces'; * @typeparam T - The type of object being tracked. */ export class RestorablePool< - T extends IObservableDisposable = IObservableDisposable -> implements IObjectPool, IRestorable { + T extends IObservableDisposable = IObservableDisposable + > + implements IObjectPool, IRestorable +{ /** * Create a new restorable pool. * diff --git a/packages/statedb/src/statedb.ts b/packages/statedb/src/statedb.ts index d603d978012f..935cbd09fe6a 100644 --- a/packages/statedb/src/statedb.ts +++ b/packages/statedb/src/statedb.ts @@ -11,7 +11,8 @@ import { IStateDB } from './tokens'; */ export class StateDB< T extends ReadonlyPartialJSONValue = ReadonlyPartialJSONValue -> implements IStateDB { +> implements IStateDB +{ /** * Create a new state database. * @@ -147,10 +148,13 @@ export class StateDB< const { ids, values } = await this._list(); - return values.reduce((acc, val, idx) => { - acc[ids[idx]] = val; - return acc; - }, {} as { [id: string]: T }); + return values.reduce( + (acc, val, idx) => { + acc[ids[idx]] = val; + return acc; + }, + {} as { [id: string]: T } + ); } /** diff --git a/packages/statedb/src/tokens.ts b/packages/statedb/src/tokens.ts index a33a2385a325..6457c933145a 100644 --- a/packages/statedb/src/tokens.ts +++ b/packages/statedb/src/tokens.ts @@ -4,12 +4,15 @@ import { ReadonlyPartialJSONValue, Token } from '@lumino/coreutils'; import { IDataConnector } from './interfaces'; -/* tslint:disable */ /** * The default state database token. */ -export const IStateDB = new Token('@jupyterlab/coreutils:IStateDB'); -/* tslint:enable */ +export const IStateDB = new Token( + '@jupyterlab/coreutils:IStateDB', + `A service for the JupyterLab state database. + Use this if you want to store data that will persist across page loads. + See "state database" for more information.` +); /** * The description of a state database. diff --git a/packages/statedb/test/restorablepool.spec.ts b/packages/statedb/test/restorablepool.spec.ts index c27b44477eb5..852cae867c7f 100644 --- a/packages/statedb/test/restorablepool.spec.ts +++ b/packages/statedb/test/restorablepool.spec.ts @@ -2,7 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { RestorablePool } from '@jupyterlab/statedb'; -import { signalToPromise } from '@jupyterlab/testutils'; +import { signalToPromise } from '@jupyterlab/testing'; import { IObservableDisposable } from '@lumino/disposable'; import { ISignal, Signal } from '@lumino/signaling'; @@ -87,13 +87,21 @@ describe('@jupyterlab/coreutils', () => { }); describe('#currentChanged', () => { + let instance: ObservableDisposable; + + beforeEach(() => { + instance = new ObservableDisposable(); + }); + + afterEach(() => { + instance.dispose(); + }); + it('should emit when the current object has been updated', async () => { - const instance = new ObservableDisposable(); const promise = signalToPromise(pool.currentChanged); void pool.add(instance); pool.current = instance; - await promise; - instance.dispose(); + await expect(promise).resolves.not.toThrow(); }); }); diff --git a/packages/statedb/tsconfig.test.json b/packages/statedb/tsconfig.test.json index 717c38a1f87b..e96af67102d5 100644 --- a/packages/statedb/tsconfig.test.json +++ b/packages/statedb/tsconfig.test.json @@ -6,7 +6,7 @@ "path": "." }, { - "path": "../../testutils" + "path": "../testing" } ] } diff --git a/packages/statusbar-extension/package.json b/packages/statusbar-extension/package.json index 173ce4e50bf2..0740b01f7ab8 100644 --- a/packages/statusbar-extension/package.json +++ b/packages/statusbar-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/statusbar-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Statusbar Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -27,7 +27,8 @@ "lib/**/*.js", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", "schema/*.json", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -36,26 +37,18 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/cells": "^3.6.6", - "@jupyterlab/console": "^3.6.6", - "@jupyterlab/docregistry": "^3.6.6", - "@jupyterlab/fileeditor": "^3.6.6", - "@jupyterlab/notebook": "^3.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/statusbar": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/commands": "^1.19.0", - "@lumino/widgets": "^1.37.2" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@jupyterlab/statusbar": "^4.0.8", + "@jupyterlab/translation": "^4.0.8" }, "devDependencies": { - "@types/react": "^17.0.0", - "@types/react-dom": "^17.0.0", + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.9", "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/statusbar-extension/schema/plugin.json b/packages/statusbar-extension/schema/plugin.json index fd079e27f92e..807f2a01b122 100644 --- a/packages/statusbar-extension/schema/plugin.json +++ b/packages/statusbar-extension/schema/plugin.json @@ -7,16 +7,16 @@ "id": "jp-mainmenu-view", "items": [ { - "type": "separator", - "rank": 1 - }, - { - "command": "statusbar:toggle", - "rank": 1 - }, - { - "type": "separator", - "rank": 1 + "type": "submenu", + "submenu": { + "id": "jp-mainmenu-view-appearance", + "items": [ + { + "command": "statusbar:toggle", + "rank": 15 + } + ] + } } ] } diff --git a/packages/statusbar-extension/src/index.ts b/packages/statusbar-extension/src/index.ts index fc7f8c37a42f..03ec3704f62f 100644 --- a/packages/statusbar-extension/src/index.ts +++ b/packages/statusbar-extension/src/index.ts @@ -10,45 +10,19 @@ import { JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; -import { - ICommandPalette, - ISessionContext, - ISessionContextDialogs, - sessionContextDialogs -} from '@jupyterlab/apputils'; -import { Cell, CodeCell } from '@jupyterlab/cells'; -import { - CodeConsole, - ConsolePanel, - IConsoleTracker -} from '@jupyterlab/console'; -import { IDocumentWidget } from '@jupyterlab/docregistry'; -import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor'; -import { - INotebookTracker, - Notebook, - NotebookPanel -} from '@jupyterlab/notebook'; +import { ICommandPalette } from '@jupyterlab/apputils'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; -import { - IStatusBar, - KernelStatus, - LineCol, - RunningSessions, - StatusBar -} from '@jupyterlab/statusbar'; +import { IStatusBar, StatusBar } from '@jupyterlab/statusbar'; import { ITranslator } from '@jupyterlab/translation'; -import { Switch } from '@jupyterlab/ui-components'; -import { CommandRegistry } from '@lumino/commands'; -import { Title, Widget } from '@lumino/widgets'; -export const STATUSBAR_PLUGIN_ID = '@jupyterlab/statusbar-extension:plugin'; +const STATUSBAR_PLUGIN_ID = '@jupyterlab/statusbar-extension:plugin'; /** * Initialization data for the statusbar extension. */ const statusBar: JupyterFrontEndPlugin = { id: STATUSBAR_PLUGIN_ID, + description: 'Provides the application status bar.', requires: [ITranslator], provides: IStatusBar, autoStart: true, @@ -76,7 +50,7 @@ const statusBar: JupyterFrontEndPlugin = { app.commands.addCommand(command, { label: trans.__('Show Status Bar'), - execute: (args: any) => { + execute: () => { statusBar.setHidden(statusBar.isVisible); if (settingRegistry) { void settingRegistry.set( @@ -89,6 +63,14 @@ const statusBar: JupyterFrontEndPlugin = { isToggled: () => statusBar.isVisible }); + app.commands.commandExecuted.connect((registry, executed) => { + if (executed.id === 'application:reset-layout' && !statusBar.isVisible) { + app.commands.execute(command).catch(reason => { + console.error('Failed to show the status bar.', reason); + }); + } + }); + if (palette) { palette.addItem({ command, category }); } @@ -117,297 +99,4 @@ const statusBar: JupyterFrontEndPlugin = { optional: [ILabShell, ISettingRegistry, ICommandPalette] }; -/** - * A plugin that provides a kernel status item to the status bar. - */ -export const kernelStatus: JupyterFrontEndPlugin = { - id: '@jupyterlab/statusbar-extension:kernel-status', - autoStart: true, - requires: [ - IStatusBar, - INotebookTracker, - IConsoleTracker, - ILabShell, - ITranslator - ], - optional: [ISessionContextDialogs], - activate: ( - app: JupyterFrontEnd, - statusBar: IStatusBar, - notebookTracker: INotebookTracker, - consoleTracker: IConsoleTracker, - labShell: ILabShell, - translator: ITranslator, - sessionDialogs: ISessionContextDialogs | null - ) => { - // When the status item is clicked, launch the kernel - // selection dialog for the current session. - let currentSession: ISessionContext | null = null; - const changeKernel = async () => { - if (!currentSession) { - return; - } - await (sessionDialogs || sessionContextDialogs).selectKernel( - currentSession, - translator - ); - }; - - // Create the status item. - const item = new KernelStatus({ onClick: changeKernel }, translator); - - // When the title of the active widget changes, update the label - // of the hover text. - const onTitleChanged = (title: Title) => { - item.model!.activityName = title.label; - }; - - // Keep the session object on the status item up-to-date. - labShell.currentChanged.connect((_, change) => { - const { oldValue, newValue } = change; - - // Clean up after the old value if it exists, - // listen for changes to the title of the activity - if (oldValue) { - oldValue.title.changed.disconnect(onTitleChanged); - } - if (newValue) { - newValue.title.changed.connect(onTitleChanged); - } - - // Grab the session off of the current widget, if it exists. - if (newValue && consoleTracker.has(newValue)) { - currentSession = (newValue as ConsolePanel).sessionContext; - } else if (newValue && notebookTracker.has(newValue)) { - currentSession = (newValue as NotebookPanel).sessionContext; - } else { - currentSession = null; - } - item.model!.sessionContext = currentSession; - }); - - statusBar.registerStatusItem( - '@jupyterlab/statusbar-extension:kernel-status', - { - item, - align: 'left', - rank: 1, - isActive: () => { - const current = labShell.currentWidget; - return ( - !!current && - (notebookTracker.has(current) || consoleTracker.has(current)) - ); - } - } - ); - } -}; - -/** - * A plugin providing a line/column status item to the application. - */ -export const lineColItem: JupyterFrontEndPlugin = { - id: '@jupyterlab/statusbar-extension:line-col-status', - autoStart: true, - requires: [ - IStatusBar, - INotebookTracker, - IEditorTracker, - IConsoleTracker, - ILabShell, - ITranslator - ], - activate: ( - _: JupyterFrontEnd, - statusBar: IStatusBar, - notebookTracker: INotebookTracker, - editorTracker: IEditorTracker, - consoleTracker: IConsoleTracker, - labShell: ILabShell, - translator: ITranslator - ) => { - const item = new LineCol(translator); - - const onActiveCellChanged = (notebook: Notebook, cell: Cell) => { - item.model!.editor = cell && cell.editor; - }; - - const onPromptCreated = (console: CodeConsole, prompt: CodeCell) => { - item.model!.editor = prompt && prompt.editor; - }; - - labShell.currentChanged.connect((_, change) => { - const { oldValue, newValue } = change; - - // Check if we need to disconnect the console listener - // or the notebook active cell listener - if (oldValue && consoleTracker.has(oldValue)) { - (oldValue as ConsolePanel).console.promptCellCreated.disconnect( - onPromptCreated - ); - } else if (oldValue && notebookTracker.has(oldValue)) { - (oldValue as NotebookPanel).content.activeCellChanged.disconnect( - onActiveCellChanged - ); - } - - // Wire up the new editor to the model if it exists - if (newValue && consoleTracker.has(newValue)) { - (newValue as ConsolePanel).console.promptCellCreated.connect( - onPromptCreated - ); - const prompt = (newValue as ConsolePanel).console.promptCell; - item.model!.editor = prompt && prompt.editor; - } else if (newValue && notebookTracker.has(newValue)) { - (newValue as NotebookPanel).content.activeCellChanged.connect( - onActiveCellChanged - ); - const cell = (newValue as NotebookPanel).content.activeCell; - item.model!.editor = cell && cell.editor; - } else if (newValue && editorTracker.has(newValue)) { - item.model!.editor = (newValue as IDocumentWidget< - FileEditor - >).content.editor; - } else { - item.model!.editor = null; - } - }); - - // Add the status item to the status bar. - statusBar.registerStatusItem( - '@jupyterlab/statusbar-extension:line-col-status', - { - item, - align: 'right', - rank: 2, - isActive: () => { - const current = labShell.currentWidget; - return ( - !!current && - (notebookTracker.has(current) || - editorTracker.has(current) || - consoleTracker.has(current)) - ); - } - } - ); - } -}; - -/* - * A plugin providing running terminals and sessions information - * to the status bar. - */ -export const runningSessionsItem: JupyterFrontEndPlugin = { - id: '@jupyterlab/statusbar-extension:running-sessions-status', - autoStart: true, - requires: [IStatusBar, ITranslator], - activate: ( - app: JupyterFrontEnd, - statusBar: IStatusBar, - translator: ITranslator - ) => { - const item = new RunningSessions({ - onClick: () => app.shell.activateById('jp-running-sessions'), - serviceManager: app.serviceManager, - translator - }); - - statusBar.registerStatusItem( - '@jupyterlab/statusbar-extension:running-sessions-status', - { - item, - align: 'left', - rank: 0 - } - ); - } -}; - -/** - * The simple interface mode switch in the status bar. - */ -const modeSwitch: JupyterFrontEndPlugin = { - id: '@jupyterlab/statusbar-extension:mode-switch', - requires: [ILabShell, ITranslator, IStatusBar], - optional: [ISettingRegistry], - activate: ( - app: JupyterFrontEnd, - shell: ILabShell, - translator: ITranslator, - statusBar: IStatusBar, - settingRegistry: ISettingRegistry | null - ) => { - const trans = translator.load('jupyterlab'); - const modeSwitch = new Switch(); - modeSwitch.id = 'jp-single-document-mode'; - - modeSwitch.valueChanged.connect((_, args) => { - shell.mode = args.newValue ? 'single-document' : 'multiple-document'; - }); - shell.modeChanged.connect((_, mode) => { - modeSwitch.value = mode === 'single-document'; - }); - - if (settingRegistry) { - const loadSettings = settingRegistry.load(STATUSBAR_PLUGIN_ID); - const updateSettings = (settings: ISettingRegistry.ISettings): void => { - const startMode = settings.get('startMode').composite as string; - if (startMode) { - shell.mode = - startMode === 'single' ? 'single-document' : 'multiple-document'; - } - }; - - Promise.all([loadSettings, app.restored]) - .then(([settings]) => { - updateSettings(settings); - }) - .catch((reason: Error) => { - console.error(reason.message); - }); - } - - modeSwitch.value = shell.mode === 'single-document'; - - // Show the current file browser shortcut in its title. - const updateModeSwitchTitle = () => { - const binding = app.commands.keyBindings.find( - b => b.command === 'application:toggle-mode' - ); - if (binding) { - const ks = binding.keys.map(CommandRegistry.formatKeystroke).join(', '); - modeSwitch.caption = trans.__('Simple Interface (%1)', ks); - } else { - modeSwitch.caption = trans.__('Simple Interface'); - } - }; - updateModeSwitchTitle(); - app.commands.keyBindingChanged.connect(() => { - updateModeSwitchTitle(); - }); - - modeSwitch.label = trans.__('Simple'); - - statusBar.registerStatusItem( - '@jupyterlab/statusbar-extension:mode-switch', - { - item: modeSwitch, - align: 'left', - rank: -1 - } - ); - }, - autoStart: true -}; - -const plugins: JupyterFrontEndPlugin[] = [ - statusBar, - lineColItem, - kernelStatus, - runningSessionsItem, - modeSwitch -]; - -export default plugins; +export default statusBar; diff --git a/packages/statusbar-extension/style/index.css b/packages/statusbar-extension/style/index.css index e9283e47a781..92e10e6790b7 100644 --- a/packages/statusbar-extension/style/index.css +++ b/packages/statusbar-extension/style/index.css @@ -4,13 +4,6 @@ |----------------------------------------------------------------------------*/ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ -@import url('~@lumino/widgets/style/index.css'); -@import url('~@jupyterlab/ui-components/style/index.css'); -@import url('~@jupyterlab/apputils/style/index.css'); @import url('~@jupyterlab/statusbar/style/index.css'); -@import url('~@jupyterlab/docregistry/style/index.css'); +@import url('~@jupyterlab/apputils/style/index.css'); @import url('~@jupyterlab/application/style/index.css'); -@import url('~@jupyterlab/cells/style/index.css'); -@import url('~@jupyterlab/console/style/index.css'); -@import url('~@jupyterlab/fileeditor/style/index.css'); -@import url('~@jupyterlab/notebook/style/index.css'); diff --git a/packages/statusbar-extension/style/index.js b/packages/statusbar-extension/style/index.js index 267fc770c6ce..3f77dc11f626 100644 --- a/packages/statusbar-extension/style/index.js +++ b/packages/statusbar-extension/style/index.js @@ -4,13 +4,6 @@ |----------------------------------------------------------------------------*/ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ -import '@lumino/widgets/style/index.js'; -import '@jupyterlab/ui-components/style/index.js'; -import '@jupyterlab/apputils/style/index.js'; import '@jupyterlab/statusbar/style/index.js'; -import '@jupyterlab/docregistry/style/index.js'; +import '@jupyterlab/apputils/style/index.js'; import '@jupyterlab/application/style/index.js'; -import '@jupyterlab/cells/style/index.js'; -import '@jupyterlab/console/style/index.js'; -import '@jupyterlab/fileeditor/style/index.js'; -import '@jupyterlab/notebook/style/index.js'; diff --git a/packages/statusbar-extension/tsconfig.json b/packages/statusbar-extension/tsconfig.json index 721311d59a2e..46d8246acedc 100644 --- a/packages/statusbar-extension/tsconfig.json +++ b/packages/statusbar-extension/tsconfig.json @@ -12,21 +12,6 @@ { "path": "../apputils" }, - { - "path": "../cells" - }, - { - "path": "../console" - }, - { - "path": "../docregistry" - }, - { - "path": "../fileeditor" - }, - { - "path": "../notebook" - }, { "path": "../settingregistry" }, @@ -35,9 +20,6 @@ }, { "path": "../translation" - }, - { - "path": "../ui-components" } ] } diff --git a/packages/statusbar/.vscode/launch.json b/packages/statusbar/.vscode/launch.json index 3c841b4f2ce8..66fb4b825a88 100644 --- a/packages/statusbar/.vscode/launch.json +++ b/packages/statusbar/.vscode/launch.json @@ -12,4 +12,4 @@ "port": 9229 } ] -} \ No newline at end of file +} diff --git a/packages/statusbar/babel.config.js b/packages/statusbar/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/packages/statusbar/babel.config.js +++ b/packages/statusbar/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/packages/statusbar/jest.config.js b/packages/statusbar/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/statusbar/jest.config.js +++ b/packages/statusbar/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/statusbar/package.json b/packages/statusbar/package.json index 376bc15bcdf4..39080142062b 100644 --- a/packages/statusbar/package.json +++ b/packages/statusbar/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/statusbar", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab statusbar package.", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -22,7 +22,8 @@ "files": [ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -31,34 +32,26 @@ "docs": "typedoc src", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/codeeditor": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/messaging": "^1.10.0", - "@lumino/signaling": "^1.10.0", - "@lumino/widgets": "^1.37.2", - "csstype": "~3.0.3", - "react": "^17.0.1", - "typestyle": "^2.0.4" + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/algorithm": "^2.0.1", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/messaging": "^2.0.1", + "@lumino/signaling": "^2.1.2", + "@lumino/widgets": "^2.3.0", + "react": "^18.2.0" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "@types/resize-observer-browser": "^0.1.7", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "ts-jest": "^26.3.0", - "typescript": "~4.1.3" + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/statusbar/src/components/group.tsx b/packages/statusbar/src/components/group.tsx index c1ed52b24ae9..8a6357e640f9 100644 --- a/packages/statusbar/src/components/group.tsx +++ b/packages/statusbar/src/components/group.tsx @@ -2,10 +2,6 @@ // Distributed under the terms of the Modified BSD License. import * as React from 'react'; -import { classes, style } from 'typestyle/lib'; -import { centeredFlex, leftToRight } from '../style/layout'; - -const groupItemLayout = style(centeredFlex, leftToRight); /** * A tsx component for a set of items logically grouped together. @@ -17,7 +13,7 @@ export function GroupItem( const numChildren = React.Children.count(children); return ( -
    +
    {React.Children.map(children, (child, i) => { if (i === 0) { return
    {child}
    ; diff --git a/packages/statusbar/src/components/hover.tsx b/packages/statusbar/src/components/hover.tsx index c4b36713b61a..a1b35ec39fe6 100644 --- a/packages/statusbar/src/components/hover.tsx +++ b/packages/statusbar/src/components/hover.tsx @@ -1,15 +1,9 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { HoverBox } from '@jupyterlab/apputils'; +import { HoverBox } from '@jupyterlab/ui-components'; import { Message } from '@lumino/messaging'; import { PanelLayout, Widget } from '@lumino/widgets'; -import { style } from 'typestyle/lib'; -import { clickedItem, interactiveItem } from '../style/statusbar'; - -const hoverItem = style({ - boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)' -}); /** * Create and show a popup component. @@ -36,7 +30,7 @@ export class Popup extends Widget { constructor(options: Omit) { super(); this._body = options.body; - this._body.addClass(hoverItem); + this._body.addClass('jp-StatusBar-HoverItem'); this._anchor = options.anchor; this._align = options.align; if (options.hasDynamicSize) { @@ -54,12 +48,12 @@ export class Popup extends Widget { /** * Attach the popup widget to the page. */ - launch() { + launch(): void { this._setGeometry(); Widget.attach(this, document.body); this.update(); - this._anchor.addClass(clickedItem); - this._anchor.removeClass(interactiveItem); + this._anchor.addClass('jp-mod-clicked'); + this._anchor.removeClass('jp-mod-highlight'); } /** @@ -103,8 +97,8 @@ export class Popup extends Widget { dispose(): void { this._observer?.disconnect(); super.dispose(); - this._anchor.removeClass(clickedItem); - this._anchor.addClass(interactiveItem); + this._anchor.removeClass('jp-mod-clicked'); + this._anchor.addClass('jp-mod-highlight'); } /** diff --git a/packages/statusbar/src/components/progressCircle.tsx b/packages/statusbar/src/components/progressCircle.tsx index b17212096e3e..6ffa4d747843 100644 --- a/packages/statusbar/src/components/progressCircle.tsx +++ b/packages/statusbar/src/components/progressCircle.tsx @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import React from 'react'; export namespace ProgressCircle { /** @@ -8,9 +13,17 @@ export namespace ProgressCircle { * The current progress percentage, from 0 to 100 */ progress: number; - + /** + * The aria-label for the widget + */ + label?: string; + /** + * Element width + */ width?: number; - + /** + * Element height + */ height?: number; } } @@ -37,6 +50,7 @@ export function ProgressCircle(props: ProgressCircle.IProps): JSX.Element {
    { const { title, source, className, ...rest } = props; return ( - + {source} ); diff --git a/packages/statusbar/src/index.ts b/packages/statusbar/src/index.ts index 450fe859a3b9..3ba2cc08a963 100644 --- a/packages/statusbar/src/index.ts +++ b/packages/statusbar/src/index.ts @@ -8,7 +8,5 @@ */ export * from './components'; -export * from './defaults'; export * from './statusbar'; -export * from './style/statusbar'; export * from './tokens'; diff --git a/packages/statusbar/src/statusbar.ts b/packages/statusbar/src/statusbar.ts index 58da932baa6f..69e3d3cafe17 100644 --- a/packages/statusbar/src/statusbar.ts +++ b/packages/statusbar/src/statusbar.ts @@ -9,13 +9,6 @@ import { } from '@lumino/disposable'; import { Message } from '@lumino/messaging'; import { Panel, PanelLayout, Widget } from '@lumino/widgets'; -import { - statusBar as barStyle, - item as itemStyle, - leftSide as leftSideStyle, - rightSide as rightSideStyle, - side as sideStyle -} from './style/statusbar'; import { IStatusBar } from './tokens'; /** @@ -24,7 +17,7 @@ import { IStatusBar } from './tokens'; export class StatusBar extends Widget implements IStatusBar { constructor() { super(); - this.addClass(barStyle); + this.addClass('jp-StatusBar-Widget'); const rootLayout = (this.layout = new PanelLayout()); @@ -32,13 +25,9 @@ export class StatusBar extends Widget implements IStatusBar { const middlePanel = (this._middlePanel = new Panel()); const rightPanel = (this._rightSide = new Panel()); - leftPanel.addClass(sideStyle); - leftPanel.addClass(leftSideStyle); - - middlePanel.addClass(sideStyle); - - rightPanel.addClass(sideStyle); - rightPanel.addClass(rightSideStyle); + leftPanel.addClass('jp-StatusBar-Left'); + middlePanel.addClass('jp-StatusBar-Middle'); + rightPanel.addClass('jp-StatusBar-Right'); rootLayout.addWidget(leftPanel); rootLayout.addWidget(middlePanel); @@ -75,7 +64,7 @@ export class StatusBar extends Widget implements IStatusBar { const rankItem = { id, rank }; - fullStatusItem.item.addClass(itemStyle); + fullStatusItem.item.addClass('jp-StatusBar-Item'); this._statusItems[id] = fullStatusItem; if (align === 'left') { @@ -116,7 +105,7 @@ export class StatusBar extends Widget implements IStatusBar { /** * Dispose of the status bar. */ - dispose() { + dispose(): void { this._leftRankItems.length = 0; this._rightRankItems.length = 0; this._disposables.dispose(); @@ -126,7 +115,7 @@ export class StatusBar extends Widget implements IStatusBar { /** * Handle an 'update-request' message to the status bar. */ - protected onUpdateRequest(msg: Message) { + protected onUpdateRequest(msg: Message): void { this._refreshAll(); super.onUpdateRequest(msg); } diff --git a/packages/statusbar/src/style/layout.ts b/packages/statusbar/src/style/layout.ts deleted file mode 100644 index 52af1f0290e6..000000000000 --- a/packages/statusbar/src/style/layout.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { NestedCSSProperties } from 'typestyle/lib/types'; - -export const centeredFlex: NestedCSSProperties = { - display: 'flex', - alignItems: 'center' -}; - -export const leftToRight: NestedCSSProperties = { - flexDirection: 'row' -}; - -export const rightToLeft: NestedCSSProperties = { - flexDirection: 'row-reverse' -}; - -export const equiDistant: NestedCSSProperties = { - justifyContent: 'space-between' -}; diff --git a/packages/statusbar/src/style/lineForm.ts b/packages/statusbar/src/style/lineForm.ts deleted file mode 100644 index 37b12d548034..000000000000 --- a/packages/statusbar/src/style/lineForm.ts +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { style } from 'typestyle/lib'; -import { NestedCSSProperties } from 'typestyle/lib/types'; - -export const hoverItem = style({ - boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)' -}); - -export const lineFormSearch = style({ - padding: '4px 12px', - backgroundColor: 'var(--jp-layout-color2)', - boxShadow: 'var(--jp-toolbar-box-shadow)', - zIndex: 2, - fontSize: 'var(--jp-ui-font-size1)' -}); - -export const lineFormCaption = style({ - fontSize: 'var(--jp-ui-font-size0)', - lineHeight: 'var(--jp-ui-font-size1)', - marginTop: '4px', - color: 'var(--jp-ui-font-color0)' -}); - -export const baseLineForm: NestedCSSProperties = { - border: 'none', - borderRadius: '0px', - position: 'absolute', - backgroundSize: '16px', - backgroundRepeat: 'no-repeat', - backgroundPosition: 'center', - outline: 'none', - top: '0px', - right: '0px' -}; - -export const lineFormButtonDiv = style(baseLineForm, { - top: '4px', - right: '8px', - height: '24px', - padding: '0px 12px', - width: '12px' -}); - -export const lineFormButtonIcon = style(baseLineForm, { - backgroundColor: 'var(--jp-brand-color1)', - height: '100%', - width: '100%', - boxSizing: 'border-box', - padding: '4px 6px' -}); - -export const lineFormButton = style(baseLineForm, { - backgroundColor: 'transparent', - height: '100%', - width: '100%', - boxSizing: 'border-box' -}); - -export const lineFormWrapper = style({ - overflow: 'hidden', - padding: '0px 8px', - border: '1px solid var(--jp-border-color0)', - backgroundColor: 'var(--jp-input-active-background)', - height: '22px' -}); - -export const lineFormWrapperFocusWithin = style({ - border: 'var(--jp-border-width) solid var(--md-blue-500)', - boxShadow: 'inset 0 0 4px var(--md-blue-300)' -}); - -export const lineFormInput = style({ - background: 'transparent', - width: '200px', - height: '100%', - border: 'none', - outline: 'none', - color: 'var(--jp-ui-font-color0)', - lineHeight: '28px' -}); diff --git a/packages/statusbar/src/style/statusbar.ts b/packages/statusbar/src/style/statusbar.ts deleted file mode 100644 index f73a67bf2c62..000000000000 --- a/packages/statusbar/src/style/statusbar.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { style } from 'typestyle/lib'; -import { centeredFlex, leftToRight, rightToLeft } from './layout'; -import { textItem } from './text'; -import vars from './variables'; - -const itemPadding = { - paddingLeft: vars.itemPadding, - paddingRight: vars.itemPadding -}; - -const interactiveHover = { - $nest: { - '&:hover': { - backgroundColor: vars.hoverColor - } - } -}; - -const clicked = { - backgroundColor: vars.clickColor, - $nest: { - ['.' + textItem]: { - color: vars.textClickColor - } - } -}; - -export const statusBar = style( - { - background: vars.backgroundColor, - minHeight: vars.height, - justifyContent: 'space-between', - paddingLeft: vars.statusBarPadding, - paddingRight: vars.statusBarPadding - }, - centeredFlex -); - -export const side = style(centeredFlex); - -export const leftSide = style(leftToRight); - -export const rightSide = style(rightToLeft); - -export const item = style( - { - maxHeight: vars.height, - marginLeft: vars.itemMargin, - marginRight: vars.itemMargin, - height: vars.height, - whiteSpace: vars.whiteSpace, - textOverflow: vars.textOverflow, - color: vars.textColor - }, - itemPadding -); - -export const clickedItem = style(clicked); -export const interactiveItem = style(interactiveHover); diff --git a/packages/statusbar/src/style/text.ts b/packages/statusbar/src/style/text.ts deleted file mode 100644 index 6b12ae4d9f81..000000000000 --- a/packages/statusbar/src/style/text.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { style } from 'typestyle/lib'; -import { NestedCSSProperties } from 'typestyle/lib/types'; -import vars from './variables'; - -export const baseText: NestedCSSProperties = { - fontSize: vars.fontSize, - fontFamily: vars.fontFamily -}; - -export const textItem = style(baseText, { - lineHeight: '24px', - color: vars.textColor -}); diff --git a/packages/statusbar/src/style/variables.ts b/packages/statusbar/src/style/variables.ts deleted file mode 100644 index 27f0cda77b6a..000000000000 --- a/packages/statusbar/src/style/variables.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. -import { Property } from 'csstype'; - -export default { - hoverColor: 'var(--jp-layout-color3)', - clickColor: 'var(--jp-brand-color1)', - backgroundColor: 'var(--jp-layout-color2)', - height: 'var(--jp-statusbar-height)', - fontSize: 'var(--jp-ui-font-size1)', - fontFamily: 'var(--jp-ui-font-family)', - textColor: 'var(--jp-ui-font-color1)', - textClickColor: 'white', - itemMargin: '2px', - itemPadding: '6px', - statusBarPadding: '10px', - interItemHalfSpacing: '2px', // this amount accounts for half the spacing between items - whiteSpace: 'nowrap' as Property.WhiteSpace, - textOverflow: 'ellipsis' -}; diff --git a/packages/statusbar/src/tokens.ts b/packages/statusbar/src/tokens.ts index 6abbbce4a232..aae17a74675f 100644 --- a/packages/statusbar/src/tokens.ts +++ b/packages/statusbar/src/tokens.ts @@ -8,7 +8,8 @@ import { Widget } from '@lumino/widgets'; // tslint:disable-next-line:variable-name export const IStatusBar = new Token( - '@jupyterlab/statusbar:IStatusBar' + '@jupyterlab/statusbar:IStatusBar', + 'A service for the status bar on the application. Use this if you want to add new status bar items.' ); /** diff --git a/packages/statusbar/style/base.css b/packages/statusbar/style/base.css index 4d0d42bb0b7f..e8ff7f090a14 100644 --- a/packages/statusbar/style/base.css +++ b/packages/statusbar/style/base.css @@ -4,14 +4,77 @@ |----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- -| Variables +| Styles |----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------- +.jp-StatusBar-Widget { + display: flex; + align-items: center; + background: var(--jp-layout-color2); + min-height: var(--jp-statusbar-height); + justify-content: space-between; + padding: 0 10px; +} -/*----------------------------------------------------------------------------- -| Styles -|----------------------------------------------------------------------------*/ +.jp-StatusBar-Left { + display: flex; + align-items: center; + flex-direction: row; +} + +.jp-StatusBar-Middle { + display: flex; + align-items: center; +} + +.jp-StatusBar-Right { + display: flex; + align-items: center; + flex-direction: row-reverse; +} + +.jp-StatusBar-Item { + max-height: var(--jp-statusbar-height); + margin: 0 2px; + height: var(--jp-statusbar-height); + white-space: nowrap; + text-overflow: ellipsis; + color: var(--jp-ui-font-color1); + padding: 0 6px; +} + +.jp-mod-highlighted:hover { + background-color: var(--jp-layout-color3); +} + +.jp-mod-clicked { + background-color: var(--jp-brand-color1); +} + +.jp-mod-clicked:hover { + background-color: var(--jp-brand-color0); +} + +.jp-mod-clicked .jp-StatusBar-TextItem { + color: var(--jp-ui-inverse-font-color1); +} + +.jp-StatusBar-HoverItem { + box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25); +} + +.jp-StatusBar-TextItem { + font-size: var(--jp-ui-font-size1); + font-family: var(--jp-ui-font-family); + line-height: 24px; + color: var(--jp-ui-font-color1); +} + +.jp-StatusBar-GroupItem { + display: flex; + align-items: center; + flex-direction: row; +} .jp-Statusbar-ProgressCircle svg { display: block; @@ -20,6 +83,7 @@ height: 24px; align-self: normal; } + .jp-Statusbar-ProgressCircle path { fill: var(--jp-inverse-layout-color3); } @@ -32,6 +96,7 @@ overflow: hidden; align-self: center; } + .jp-Statusbar-ProgressBar-progress-bar > div { background-color: var(--jp-brand-color2); background-image: linear-gradient( @@ -50,7 +115,7 @@ height: 100%; font-size: 12px; line-height: 14px; - color: #ffffff; + color: #fff; text-align: center; animation: jp-Statusbar-ExecutionTime-progress-bar 2s linear infinite; } @@ -67,6 +132,7 @@ 0% { background-position: 0 0; } + 100% { background-position: 40px 40px; } diff --git a/packages/statusbar/style/index.css b/packages/statusbar/style/index.css index 74470e295cca..f2a875036f3f 100644 --- a/packages/statusbar/style/index.css +++ b/packages/statusbar/style/index.css @@ -6,7 +6,4 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ @import url('~@lumino/widgets/style/index.css'); @import url('~@jupyterlab/ui-components/style/index.css'); -@import url('~@jupyterlab/apputils/style/index.css'); -@import url('~@jupyterlab/codeeditor/style/index.css'); - @import url('./base.css'); diff --git a/packages/statusbar/style/index.js b/packages/statusbar/style/index.js index 0867489da1b3..d7ce681a90b2 100644 --- a/packages/statusbar/style/index.js +++ b/packages/statusbar/style/index.js @@ -6,7 +6,5 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ import '@lumino/widgets/style/index.js'; import '@jupyterlab/ui-components/style/index.js'; -import '@jupyterlab/apputils/style/index.js'; -import '@jupyterlab/codeeditor/style/index.js'; import './base.css'; diff --git a/packages/statusbar/test/statusbar.spec.ts b/packages/statusbar/test/statusbar.spec.ts index 5356c2607a05..b44c53768cb4 100644 --- a/packages/statusbar/test/statusbar.spec.ts +++ b/packages/statusbar/test/statusbar.spec.ts @@ -41,7 +41,7 @@ describe('@jupyterlab/statusbar', () => { statusBar.registerStatusItem('item', { item: item1 }); expect( statusBar.registerStatusItem.bind(statusBar, 'item', { item: item2 }) - ).toThrowError(); + ).toThrow(); }); it('should put higher rank left items closer to the middle', () => { diff --git a/packages/statusbar/tsconfig.json b/packages/statusbar/tsconfig.json index ebf71d5042c8..1b9e4bfd7f12 100644 --- a/packages/statusbar/tsconfig.json +++ b/packages/statusbar/tsconfig.json @@ -2,24 +2,10 @@ "extends": "../../tsconfigbase", "compilerOptions": { "outDir": "lib", - "rootDir": "src", - "lib": ["DOM", "ES2018"], - "types": ["resize-observer-browser"] + "rootDir": "src" }, "include": ["src/**/*"], "references": [ - { - "path": "../apputils" - }, - { - "path": "../codeeditor" - }, - { - "path": "../services" - }, - { - "path": "../translation" - }, { "path": "../ui-components" } diff --git a/packages/statusbar/tsconfig.test.json b/packages/statusbar/tsconfig.test.json index 8b62212e97dd..db1fe391e837 100644 --- a/packages/statusbar/tsconfig.test.json +++ b/packages/statusbar/tsconfig.test.json @@ -2,18 +2,6 @@ "extends": "../../tsconfigbase.test", "include": ["src/*", "test/*"], "references": [ - { - "path": "../apputils" - }, - { - "path": "../codeeditor" - }, - { - "path": "../services" - }, - { - "path": "../translation" - }, { "path": "../ui-components" }, @@ -21,22 +9,7 @@ "path": "." }, { - "path": "../../testutils" - }, - { - "path": "../apputils" - }, - { - "path": "../codeeditor" - }, - { - "path": "../services" - }, - { - "path": "../translation" - }, - { - "path": "../ui-components" + "path": "../testing" } ] } diff --git a/packages/terminal-extension/package.json b/packages/terminal-extension/package.json index 5bc354245038..cdb3281d466d 100644 --- a/packages/terminal-extension/package.json +++ b/packages/terminal-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/terminal-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Terminal Emulator Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -28,7 +28,8 @@ "lib/*.js", "schema/*.json", "style/**/*.css", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -37,24 +38,23 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/launcher": "^3.6.6", - "@jupyterlab/mainmenu": "^3.6.6", - "@jupyterlab/running": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/terminal": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/widgets": "^1.37.2" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/launcher": "^4.0.8", + "@jupyterlab/mainmenu": "^4.0.8", + "@jupyterlab/running": "^4.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@jupyterlab/terminal": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { - "@types/webpack-env": "^1.14.1", + "@types/webpack-env": "^1.18.0", "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/terminal-extension/src/index.ts b/packages/terminal-extension/src/index.ts index 961556878192..34c932c17913 100644 --- a/packages/terminal-extension/src/index.ts +++ b/packages/terminal-extension/src/index.ts @@ -18,22 +18,23 @@ import { WidgetTracker } from '@jupyterlab/apputils'; import { ILauncher } from '@jupyterlab/launcher'; -import { IFileMenu, IMainMenu } from '@jupyterlab/mainmenu'; +import { IMainMenu } from '@jupyterlab/mainmenu'; import { IRunningSessionManagers, IRunningSessions } from '@jupyterlab/running'; import { Terminal, TerminalAPI } from '@jupyterlab/services'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; -import { ITerminal, ITerminalTracker } from '@jupyterlab/terminal'; -// Name-only import so as to not trigger inclusion in main bundle -import * as WidgetModuleType from '@jupyterlab/terminal/lib/widget'; +import { + ITerminal, + ITerminalTracker, + Terminal as XTerm +} from '@jupyterlab/terminal'; import { ITranslator } from '@jupyterlab/translation'; -import { toArray } from '@lumino/algorithm'; import { copyIcon, pasteIcon, refreshIcon, terminalIcon } from '@jupyterlab/ui-components'; -import { Menu } from '@lumino/widgets'; +import { Menu, Widget } from '@lumino/widgets'; /** * The command IDs used by the terminal plugin. @@ -54,6 +55,8 @@ namespace CommandIDs { export const paste = 'terminal:paste'; export const setTheme = 'terminal:set-theme'; + + export const shutdown = 'terminal:shut-down'; } /** @@ -62,6 +65,7 @@ namespace CommandIDs { const plugin: JupyterFrontEndPlugin = { activate, id: '@jupyterlab/terminal-extension:plugin', + description: 'Adds terminal and provides its tracker.', provides: ITerminalTracker, requires: [ISettingRegistry, ITranslator], optional: [ @@ -224,13 +228,9 @@ function activate( // Add terminal close-and-shutdown to the file menu. mainMenu.fileMenu.closeAndCleaners.add({ - tracker, - closeAndCleanupLabel: (n: number) => trans.__('Shutdown Terminal'), - closeAndCleanup: (current: MainAreaWidget) => { - // The widget is automatically disposed upon session shutdown. - return current.content.session.shutdown(); - } - } as IFileMenu.ICloseAndCleaner>); + id: CommandIDs.shutdown, + isEnabled: (w: Widget) => tracker.currentWidget !== null && tracker.has(w) + }); } if (palette) { @@ -292,20 +292,6 @@ function addRunningSessionManager( const trans = translator.load('jupyterlab'); const manager = app.serviceManager.terminals; - managers.add({ - name: trans.__('Terminals'), - running: () => - toArray(manager.running()).map(model => new RunningTerminal(model)), - shutdownAll: () => manager.shutdownAll(), - refreshRunning: () => manager.refreshRunning(), - runningChanged: manager.runningChanged, - shutdownLabel: trans.__('Shut Down'), - shutdownAllLabel: trans.__('Shut Down All'), - shutdownAllConfirmationText: trans.__( - 'Are you sure you want to permanently shut down all running terminals?' - ) - }); - class RunningTerminal implements IRunningSessions.IRunningItem { constructor(model: Terminal.IModel) { this._model = model; @@ -325,12 +311,26 @@ function addRunningSessionManager( private _model: Terminal.IModel; } + + managers.add({ + name: trans.__('Terminals'), + running: () => + Array.from(manager.running()).map(model => new RunningTerminal(model)), + shutdownAll: () => manager.shutdownAll(), + refreshRunning: () => manager.refreshRunning(), + runningChanged: manager.runningChanged, + shutdownLabel: trans.__('Shut Down'), + shutdownAllLabel: trans.__('Shut Down All'), + shutdownAllConfirmationText: trans.__( + 'Are you sure you want to permanently shut down all running terminals?' + ) + }); } /** * Add the commands for the terminal. */ -export function addCommands( +function addCommands( app: JupyterFrontEnd, tracker: WidgetTracker>, settingRegistry: ISettingRegistry, @@ -351,17 +351,11 @@ export function addCommands( caption: trans.__('Start a new terminal session'), icon: args => (args['isPalette'] ? undefined : terminalIcon), execute: async args => { - // wait for the widget to lazy load - let Terminal: typeof WidgetModuleType.Terminal; - try { - Terminal = (await Private.ensureWidget()).Terminal; - } catch (err) { - Private.showErrorMessage(err); - return; - } - const name = args['name'] as string; const cwd = args['cwd'] as string; + const localPath = cwd + ? serviceManager.contents.localPath(cwd) + : undefined; let session; if (name) { @@ -373,21 +367,24 @@ export function addCommands( } else { // we are restoring a terminal widget but the corresponding terminal was closed // let's start a new terminal with the original name - session = await serviceManager.terminals.startNew({ name, cwd }); + session = await serviceManager.terminals.startNew({ + name, + cwd: localPath + }); } } else { // we are creating a new terminal widget with a new terminal // let the server choose the terminal name - session = await serviceManager.terminals.startNew({ cwd }); + session = await serviceManager.terminals.startNew({ cwd: localPath }); } - const term = new Terminal(session, options, translator); + const term = new XTerm(session, options, translator); term.title.icon = terminalIcon; term.title.label = '...'; - const main = new MainAreaWidget({ content: term }); - app.shell.add(main); + const main = new MainAreaWidget({ content: term, reveal: term.ready }); + app.shell.add(main, 'main', { type: 'Terminal' }); void tracker.add(main); app.shell.activateById(main.id); return main; @@ -395,6 +392,7 @@ export function addCommands( }); commands.addCommand(CommandIDs.open, { + label: trans.__('Open a terminal by its `name`.'), execute: args => { const name = args['name'] as string; // Check for a running terminal with the given name. @@ -447,7 +445,7 @@ export function addCommands( return; } - const text = widget.getSelection!(); + const text = widget.getSelection(); if (text) { Clipboard.copyToSystem(text); @@ -464,12 +462,8 @@ export function addCommands( return false; } - if (!widget.hasSelection) { - return false; - } - // Enable command if there is a text selection in the terminal - return widget.hasSelection!(); + return widget.hasSelection(); }, icon: copyIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Copy') @@ -492,24 +486,26 @@ export function addCommands( if (clipboardData) { // Paste data to the terminal - widget.paste!(clipboardData); + widget.paste(clipboardData); } }, - isEnabled: () => { - const widget = tracker.currentWidget?.content; - - if (!widget) { - return false; - } + isEnabled: () => Boolean(isEnabled() && tracker.currentWidget?.content), + icon: pasteIcon.bindprops({ stylesheet: 'menuItem' }), + label: trans.__('Paste') + }); - if (!widget.paste) { - return false; + commands.addCommand(CommandIDs.shutdown, { + label: trans.__('Shutdown Terminal'), + execute: () => { + const current = tracker.currentWidget; + if (!current) { + return; } - return isEnabled(); + // The widget is automatically disposed upon session shutdown. + return current.content.session.shutdown(); }, - icon: pasteIcon.bindprops({ stylesheet: 'menuItem' }), - label: trans.__('Paste') + isEnabled }); commands.addCommand(CommandIDs.increaseFont, { @@ -548,6 +544,9 @@ export function addCommands( commands.addCommand(CommandIDs.setTheme, { label: args => { + if (args.theme === undefined) { + return trans.__('Set terminal theme to the provided `theme`.'); + } const theme = args['theme'] as string; const displayName = theme in themeDisplayedName @@ -579,24 +578,6 @@ export function addCommands( * A namespace for private data. */ namespace Private { - /** - * A Promise for the initial load of the terminal widget. - */ - export let widgetReady: Promise; - - /** - * Lazy-load the widget (and xterm library and addons) - */ - export function ensureWidget(): Promise { - if (widgetReady) { - return widgetReady; - } - - widgetReady = import('@jupyterlab/terminal/lib/widget'); - - return widgetReady; - } - /** * Utility function for consistent error reporting */ diff --git a/packages/terminal/.vscode/launch.json b/packages/terminal/.vscode/launch.json index 3c841b4f2ce8..66fb4b825a88 100644 --- a/packages/terminal/.vscode/launch.json +++ b/packages/terminal/.vscode/launch.json @@ -12,4 +12,4 @@ "port": 9229 } ] -} \ No newline at end of file +} diff --git a/packages/terminal/babel.config.js b/packages/terminal/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/packages/terminal/babel.config.js +++ b/packages/terminal/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/packages/terminal/jest.config.js b/packages/terminal/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/terminal/jest.config.js +++ b/packages/terminal/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/terminal/package.json b/packages/terminal/package.json index 61bc470b0377..61d51d20d530 100644 --- a/packages/terminal/package.json +++ b/packages/terminal/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/terminal", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Terminal Emulator Widget", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -27,7 +27,8 @@ "lib/*.js.map", "lib/*.js", "style/*.css", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -36,31 +37,32 @@ "docs": "typedoc src", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/translation": "^3.6.6", - "@lumino/coreutils": "^1.11.0", - "@lumino/domutils": "^1.8.0", - "@lumino/messaging": "^1.10.0", - "@lumino/widgets": "^1.37.2", - "xterm": "~4.19.0", - "xterm-addon-fit": "~0.5.0", - "xterm-addon-web-links": "~0.6.0" + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/translation": "^4.0.8", + "@lumino/coreutils": "^2.1.2", + "@lumino/domutils": "^2.0.1", + "@lumino/messaging": "^2.0.1", + "@lumino/widgets": "^2.3.0", + "xterm": "~5.1.0", + "xterm-addon-canvas": "~0.3.0", + "xterm-addon-fit": "~0.7.0", + "xterm-addon-web-links": "~0.8.0", + "xterm-addon-webgl": "~0.14.0" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "canvas": "^2.6.1", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "canvas": "^2.11.2", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "ts-jest": "^26.3.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/terminal/src/tokens.ts b/packages/terminal/src/tokens.ts index f639307cdb1e..3205448bb82a 100644 --- a/packages/terminal/src/tokens.ts +++ b/packages/terminal/src/tokens.ts @@ -12,14 +12,15 @@ import { Widget } from '@lumino/widgets'; export interface ITerminalTracker extends IWidgetTracker> {} -/* tslint:disable */ /** * The editor tracker token. */ export const ITerminalTracker = new Token( - '@jupyterlab/terminal:ITerminalTracker' + '@jupyterlab/terminal:ITerminalTracker', + `A widget tracker for terminals. + Use this if you want to be able to iterate over and interact with terminals + created by the application.` ); -/* tslint:enable */ /** * The namespace for terminals. Separated from the widget so it can be lazy @@ -50,17 +51,17 @@ export namespace ITerminal { /** * Check if terminal has any text selected. */ - hasSelection?(): boolean; + hasSelection(): boolean; /** * Paste text into terminal. */ - paste?(data: string): void; + paste(data: string): void; /** * Get selected text from terminal. */ - getSelection?(): string | null; + getSelection(): string | null; } /** * Options for the terminal widget. @@ -167,6 +168,7 @@ export namespace ITerminal { background: string; cursor: string; cursorAccent: string; - selection: string; + selectionBackground: string; + selectionInactiveBackground: string; } } diff --git a/packages/terminal/src/widget.ts b/packages/terminal/src/widget.ts index 2a86443e4ee2..52e83b6b120a 100644 --- a/packages/terminal/src/widget.ts +++ b/packages/terminal/src/widget.ts @@ -7,12 +7,19 @@ import { nullTranslator, TranslationBundle } from '@jupyterlab/translation'; +import { PromiseDelegate } from '@lumino/coreutils'; import { Platform } from '@lumino/domutils'; import { Message, MessageLoop } from '@lumino/messaging'; import { Widget } from '@lumino/widgets'; -import { Terminal as Xterm } from 'xterm'; -import { FitAddon } from 'xterm-addon-fit'; -import { WebLinksAddon } from 'xterm-addon-web-links'; +import type { + ITerminalInitOnlyOptions, + ITerminalOptions, + Terminal as Xterm +} from 'xterm'; +import type { CanvasAddon } from 'xterm-addon-canvas'; +import type { FitAddon } from 'xterm-addon-fit'; +import type { WebLinksAddon } from 'xterm-addon-web-links'; +import type { WebglAddon } from 'xterm-addon-webgl'; import { ITerminal } from '.'; /** @@ -61,66 +68,68 @@ export class Terminal extends Widget implements ITerminal.ITerminal { this._setThemeAttribute(theme); - // Create the xterm. - this._term = new Xterm(xtermOptions); - this._fitAddon = new FitAddon(); - this._webLinksAddon = new WebLinksAddon(); - this._term.loadAddon(this._fitAddon); - this._term.loadAddon(this._webLinksAddon); - - this._initializeTerm(); - - this.id = `jp-Terminal-${Private.id++}`; - this.title.label = this._trans.__('Terminal'); - - session.messageReceived.connect(this._onMessage, this); + // Buffer session message while waiting for the terminal + let buffer = ''; + const bufferMessage = ( + sender: TerminalNS.ITerminalConnection, + msg: TerminalNS.IMessage + ): void => { + switch (msg.type) { + case 'stdout': + if (msg.content) { + buffer += msg.content[0] as string; + } + break; + default: + break; + } + }; + session.messageReceived.connect(bufferMessage); session.disposed.connect(() => { if (this.getOption('closeOnExit')) { this.dispose(); } }, this); - if (session.connectionStatus === 'connected') { - this._initialConnection(); - } else { - session.connectionStatusChanged.connect(this._initialConnection, this); - } - } - - private _setThemeAttribute(theme: string | null | undefined) { - if (this.isDisposed) { - return; - } - - this.node.setAttribute( - 'data-term-theme', - theme ? theme.toLowerCase() : 'inherit' - ); - } - - private _initialConnection() { - if (this.isDisposed) { - return; - } - - if (this.session.connectionStatus !== 'connected') { - return; - } - - this.title.label = this._trans.__('Terminal %1', this.session.name); - this._setSessionSize(); - if (this._options.initialCommand) { - this.session.send({ - type: 'stdin', - content: [this._options.initialCommand + '\r'] + // Create the xterm. + Private.createTerminal(xtermOptions) + .then(([term, fitAddon]) => { + this._term = term; + this._fitAddon = fitAddon; + this._initializeTerm(); + + this.id = `jp-Terminal-${Private.id++}`; + this.title.label = this._trans.__('Terminal'); + this._isReady = true; + this._ready.resolve(); + + if (buffer) { + this._term.write(buffer); + } + session.messageReceived.disconnect(bufferMessage); + session.messageReceived.connect(this._onMessage, this); + + if (session.connectionStatus === 'connected') { + this._initialConnection(); + } else { + session.connectionStatusChanged.connect( + this._initialConnection, + this + ); + } + this.update(); + }) + .catch(reason => { + console.error('Failed to create a terminal.\n', reason); + this._ready.reject(reason); }); - } + } - // Only run this initial connection logic once. - this.session.connectionStatusChanged.disconnect( - this._initialConnection, - this - ); + /** + * A promise that is fulfilled when the terminal is ready. + */ + get ready(): Promise { + return this._ready.promise; } /** @@ -154,18 +163,32 @@ export class Terminal extends Widget implements ITerminal.ITerminal { this._options[option] = value; switch (option) { - case 'shutdownOnClose': // Do not transmit to XTerm - case 'closeOnExit': // Do not transmit to XTerm + case 'fontFamily': + this._term.options.fontFamily = value as string | undefined; + break; + case 'fontSize': + this._term.options.fontSize = value as number | undefined; + break; + case 'lineHeight': + this._term.options.lineHeight = value as number | undefined; + break; + case 'screenReaderMode': + this._term.options.screenReaderMode = value as boolean | undefined; + break; + case 'scrollback': + this._term.options.scrollback = value as number | undefined; break; case 'theme': - this._term.setOption( - 'theme', - Private.getXTermTheme(value as ITerminal.Theme) - ); + this._term.options.theme = { + ...Private.getXTermTheme(value as ITerminal.Theme) + }; this._setThemeAttribute(value as ITerminal.Theme); break; + case 'macOptionIsMeta': + this._term.options.macOptionIsMeta = value as boolean | undefined; + break; default: - this._term.setOption(option, value); + // Do not transmit options not listed above to XTerm break; } @@ -184,7 +207,9 @@ export class Terminal extends Widget implements ITerminal.ITerminal { }); } } - this._term.dispose(); + void this.ready.then(() => { + this._term.dispose(); + }); super.dispose(); } @@ -195,7 +220,7 @@ export class Terminal extends Widget implements ITerminal.ITerminal { * Failure to reconnect to the session should be caught appropriately */ async refresh(): Promise { - if (!this.isDisposed) { + if (!this.isDisposed && this._isReady) { await this.session.reconnect(); this._term.clear(); } @@ -205,7 +230,7 @@ export class Terminal extends Widget implements ITerminal.ITerminal { * Check if terminal has any text selected. */ hasSelection(): boolean { - if (!this.isDisposed) { + if (!this.isDisposed && this._isReady) { return this._term.hasSelection(); } return false; @@ -215,7 +240,7 @@ export class Terminal extends Widget implements ITerminal.ITerminal { * Paste text into terminal. */ paste(data: string): void { - if (!this.isDisposed) { + if (!this.isDisposed && this._isReady) { return this._term.paste(data); } } @@ -224,7 +249,7 @@ export class Terminal extends Widget implements ITerminal.ITerminal { * Get selected text from terminal. */ getSelection(): string | null { - if (!this.isDisposed) { + if (!this.isDisposed && this._isReady) { return this._term.getSelection(); } return null; @@ -277,7 +302,7 @@ export class Terminal extends Widget implements ITerminal.ITerminal { * A message handler invoked on an `'update-request'` message. */ protected onUpdateRequest(msg: Message): void { - if (!this.isVisible || !this.isAttached) { + if (!this.isVisible || !this.isAttached || !this._isReady) { return; } @@ -305,7 +330,32 @@ export class Terminal extends Widget implements ITerminal.ITerminal { * Handle `'activate-request'` messages. */ protected onActivateRequest(msg: Message): void { - this._term.focus(); + this._term?.focus(); + } + + private _initialConnection() { + if (this.isDisposed) { + return; + } + + if (this.session.connectionStatus !== 'connected') { + return; + } + + this.title.label = this._trans.__('Terminal %1', this.session.name); + this._setSessionSize(); + if (this._options.initialCommand) { + this.session.send({ + type: 'stdin', + content: [this._options.initialCommand + '\r'] + }); + } + + // Only run this initial connection logic once. + this.session.connectionStatusChanged.disconnect( + this._initialConnection, + this + ); } /** @@ -402,15 +452,27 @@ export class Terminal extends Widget implements ITerminal.ITerminal { } } - private readonly _term: Xterm; - private readonly _fitAddon: FitAddon; - private readonly _webLinksAddon: WebLinksAddon; - private _trans: TranslationBundle; + private _setThemeAttribute(theme: string | null | undefined) { + if (this.isDisposed) { + return; + } + + this.node.setAttribute( + 'data-term-theme', + theme ? theme.toLowerCase() : 'inherit' + ); + } + + private _fitAddon: FitAddon; private _needsResize = true; - private _termOpened = false; private _offsetWidth = -1; private _offsetHeight = -1; private _options: ITerminal.IOptions; + private _isReady = false; + private _ready = new PromiseDelegate(); + private _term: Xterm; + private _termOpened = false; + private _trans: TranslationBundle; } /** @@ -430,7 +492,8 @@ namespace Private { background: '#fff', cursor: '#616161', // md-grey-700 cursorAccent: '#F5F5F5', // md-grey-100 - selection: 'rgba(97, 97, 97, 0.3)' // md-grey-700 + selectionBackground: 'rgba(97, 97, 97, 0.3)', // md-grey-700 + selectionInactiveBackground: 'rgba(189, 189, 189, 0.3)' // md-grey-400 }; /** @@ -441,7 +504,8 @@ namespace Private { background: '#000', cursor: '#fff', cursorAccent: '#000', - selection: 'rgba(255, 255, 255, 0.3)' + selectionBackground: 'rgba(255, 255, 255, 0.3)', + selectionInactiveBackground: 'rgba(238, 238, 238, 0.3)' // md-grey-200 }; /** @@ -460,8 +524,11 @@ namespace Private { cursorAccent: getComputedStyle(document.body) .getPropertyValue('--jp-ui-inverse-font-color0') .trim(), - selection: getComputedStyle(document.body) - .getPropertyValue('--jp-ui-font-color3') + selectionBackground: getComputedStyle(document.body) + .getPropertyValue('--jp-layout-color3') + .trim(), + selectionInactiveBackground: getComputedStyle(document.body) + .getPropertyValue('--jp-layout-color2') .trim() }); @@ -479,3 +546,81 @@ namespace Private { } } } + +/** + * Utility functions for creating a Terminal widget + */ +namespace Private { + let supportWebGL: boolean = false; + let Xterm_: typeof Xterm; + let FitAddon_: typeof FitAddon; + let WeblinksAddon_: typeof WebLinksAddon; + let Renderer_: typeof CanvasAddon | typeof WebglAddon; + + /** + * Detect if the browser supports WebGL or not. + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/By_example/Detect_WebGL + */ + function hasWebGLContext(): boolean { + // Create canvas element. The canvas is not added to the + // document itself, so it is never displayed in the + // browser window. + const canvas = document.createElement('canvas'); + + // Get WebGLRenderingContext from canvas element. + const gl = + canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + + // Report the result. + try { + return gl instanceof WebGLRenderingContext; + } catch (error) { + return false; + } + } + + function addRenderer(term: Xterm): void { + let renderer = new Renderer_(); + term.loadAddon(renderer); + if (supportWebGL) { + (renderer as WebglAddon).onContextLoss(event => { + console.debug('WebGL context lost - reinitialize Xtermjs renderer.'); + renderer.dispose(); + // If the Webgl context is lost, reinitialize the addon + addRenderer(term); + }); + } + } + + /** + * Create a xterm.js terminal asynchronously. + */ + export async function createTerminal( + options: ITerminalOptions & ITerminalInitOnlyOptions + ): Promise<[Xterm, FitAddon]> { + if (!Xterm_) { + supportWebGL = hasWebGLContext(); + const [xterm_, fitAddon_, renderer_, weblinksAddon_] = await Promise.all([ + import('xterm'), + import('xterm-addon-fit'), + supportWebGL + ? import('xterm-addon-webgl') + : import('xterm-addon-canvas'), + import('xterm-addon-web-links') + ]); + Xterm_ = xterm_.Terminal; + FitAddon_ = fitAddon_.FitAddon; + Renderer_ = + (renderer_ as any).WebglAddon ?? (renderer_ as any).CanvasAddon; + WeblinksAddon_ = weblinksAddon_.WebLinksAddon; + } + + const term = new Xterm_(options); + addRenderer(term); + const fitAddon = new FitAddon_(); + term.loadAddon(fitAddon); + term.loadAddon(new WeblinksAddon_()); + return [term, fitAddon]; + } +} diff --git a/packages/terminal/style/index.css b/packages/terminal/style/index.css index 48173c41f65e..46146501799b 100644 --- a/packages/terminal/style/index.css +++ b/packages/terminal/style/index.css @@ -7,5 +7,4 @@ @import url('~@lumino/widgets/style/index.css'); @import url('~@jupyterlab/apputils/style/index.css'); @import url('~xterm/css/xterm.css'); - @import url('./base.css'); diff --git a/packages/terminal/test/terminal.spec.ts b/packages/terminal/test/terminal.spec.ts index 93e78f1e31d9..a42a8b3479f1 100644 --- a/packages/terminal/test/terminal.spec.ts +++ b/packages/terminal/test/terminal.spec.ts @@ -2,11 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { TerminalManager, Terminal as TerminalNS } from '@jupyterlab/services'; -import { - framePromise, - JupyterServer, - testEmission -} from '@jupyterlab/testutils'; +import { framePromise, JupyterServer, testEmission } from '@jupyterlab/testing'; import { Message, MessageLoop } from '@lumino/messaging'; import { Widget } from '@lumino/widgets'; import { Terminal } from '../src'; @@ -15,7 +11,7 @@ const server = new JupyterServer(); beforeAll(async () => { await server.start(); -}); +}, 30000); afterAll(async () => { await server.shutdown(); @@ -70,7 +66,7 @@ describe('terminal/index', () => { widget = new LogTerminal(session, { autoFit: false }); Widget.attach(widget, document.body); return framePromise(); - }); + }, 30000); afterEach(() => { widget.dispose(); @@ -138,8 +134,8 @@ describe('terminal/index', () => { }); describe('#refresh()', () => { - it('should refresh the widget', () => { - return widget.refresh(); + it('should refresh the widget', async () => { + await expect(widget.refresh()).resolves.not.toThrow(); }); }); diff --git a/packages/terminal/tsconfig.test.json b/packages/terminal/tsconfig.test.json index 561d8ca58d84..dac12683a035 100644 --- a/packages/terminal/tsconfig.test.json +++ b/packages/terminal/tsconfig.test.json @@ -15,16 +15,7 @@ "path": "." }, { - "path": "../../testutils" - }, - { - "path": "../apputils" - }, - { - "path": "../services" - }, - { - "path": "../translation" + "path": "../testing" } ] } diff --git a/packages/testing/babel.config.js b/packages/testing/babel.config.js new file mode 100644 index 000000000000..5f79707bb8bd --- /dev/null +++ b/packages/testing/babel.config.js @@ -0,0 +1,6 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('./lib/babel-config'); diff --git a/packages/testing/jest.config.js b/packages/testing/jest.config.js new file mode 100644 index 000000000000..ba98a0ed400e --- /dev/null +++ b/packages/testing/jest.config.js @@ -0,0 +1,7 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('./lib/jest-config'); +module.exports = func(__dirname); diff --git a/packages/testing/package.json b/packages/testing/package.json new file mode 100644 index 000000000000..abd4bda0a469 --- /dev/null +++ b/packages/testing/package.json @@ -0,0 +1,65 @@ +{ + "name": "@jupyterlab/testing", + "version": "4.0.8", + "description": "JupyterLab basic testing utilities.", + "homepage": "https://github.com/jupyterlab/jupyterlab", + "bugs": { + "url": "https://github.com/jupyterlab/jupyterlab/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/jupyterlab/jupyterlab.git" + }, + "license": "BSD-3-Clause", + "author": "Project Jupyter", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "directories": { + "lib": "lib/" + }, + "files": [ + "lib/**/*.{d.ts,js,js.map,json}", + "src/**/*.{ts,tsx}" + ], + "scripts": { + "build": "tsc -b", + "build:all": "npm run build", + "build:test": "tsc --build tsconfig.test.json", + "clean": "rimraf lib tsconfig.tsbuildinfo", + "test": "jest -i", + "test:cov": "jest -i --collect-coverage", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", + "watch": "tsc -b --watch" + }, + "dependencies": { + "@babel/core": "^7.10.2", + "@babel/preset-env": "^7.10.2", + "@jupyterlab/coreutils": "^6.0.8", + "@lumino/coreutils": "^2.1.2", + "@lumino/signaling": "^2.1.2", + "child_process": "~1.0.2", + "deepmerge": "^4.2.2", + "fs-extra": "^10.1.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^29.2.0", + "jest-environment-jsdom": "^29.3.0", + "jest-junit": "^15.0.0", + "node-fetch": "^2.6.0", + "simulate-event": "~1.4.0", + "ts-jest": "^29.1.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.2", + "rimraf": "~3.0.0", + "typescript": "~5.0.4" + }, + "peerDependencies": { + "typescript": ">=4.3" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/testing/src/babel-config.ts b/packages/testing/src/babel-config.ts new file mode 100644 index 000000000000..77518f05ded2 --- /dev/null +++ b/packages/testing/src/babel-config.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const babelConfig = { + presets: [ + [ + '@babel/preset-env', + { + targets: { + node: 'current' + } + } + ] + ] +}; + +export default babelConfig; diff --git a/testutils/src/common.ts b/packages/testing/src/common.ts similarity index 63% rename from testutils/src/common.ts rename to packages/testing/src/common.ts index a39ff9ef6a90..2299c1e4173a 100644 --- a/testutils/src/common.ts +++ b/packages/testing/src/common.ts @@ -1,19 +1,17 @@ -import { simulate as simulateEvent } from 'simulate-event'; - -import { ServiceManager, Session } from '@jupyterlab/services'; +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ -import { SessionContext } from '@jupyterlab/apputils'; +import { simulate as simulateEvent } from 'simulate-event'; -import { PromiseDelegate, UUID } from '@lumino/coreutils'; +import { PromiseDelegate } from '@lumino/coreutils'; import { ISignal, Signal } from '@lumino/signaling'; -import { - Context, - DocumentRegistry, - TextModelFactory -} from '@jupyterlab/docregistry'; -import { INotebookModel, NotebookModelFactory } from '@jupyterlab/notebook'; +import { sleep } from '@jupyterlab/coreutils/lib/testutils'; + +export { sleep } from '@jupyterlab/coreutils/lib/testutils'; // Add a simple polyfill for `PointerEvent` which is not yet supported by jsdom // see https://github.com/jsdom/jsdom/pull/2666 @@ -207,133 +205,6 @@ export function framePromise(): Promise { return done.promise; } -/** - * Return a promise that resolves in the given milliseconds with the given value. - */ -export function sleep(milliseconds?: number): Promise; -export function sleep(milliseconds: number, value: T): Promise; -export function sleep( - milliseconds: number = 0, - value?: any -): Promise | Promise { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(value); - }, milliseconds); - }); -} - -/** - * Create a client session object. - */ -export async function createSessionContext( - options: Partial = {} -): Promise { - const manager = options.sessionManager ?? Private.getManager().sessions; - const specsManager = options.specsManager ?? Private.getManager().kernelspecs; - - await Promise.all([manager.ready, specsManager.ready]); - return new SessionContext({ - sessionManager: manager, - specsManager, - path: options.path ?? UUID.uuid4(), - name: options.name, - type: options.type, - kernelPreference: options.kernelPreference ?? { - shouldStart: true, - canStart: true, - name: specsManager.specs?.default - } - }); -} - -/** - * Create a session and return a session connection. - */ -export async function createSession( - options: Session.ISessionOptions -): Promise { - const manager = Private.getManager().sessions; - await manager.ready; - return manager.startNew(options); -} - -/** - * Create a context for a file. - */ -export function createFileContext( - path: string = UUID.uuid4() + '.txt', - manager: ServiceManager.IManager = Private.getManager() -): Context { - const factory = Private.textFactory; - return new Context({ manager, factory, path }); -} - -export async function createFileContextWithKernel( - path: string = UUID.uuid4() + '.txt', - manager: ServiceManager.IManager = Private.getManager() -) { - const factory = Private.textFactory; - const specsManager = manager.kernelspecs; - await specsManager.ready; - - return new Context({ - manager, - factory, - path, - kernelPreference: { - shouldStart: true, - canStart: true, - name: specsManager.specs?.default - } - }); -} - -/** - * Create and initialize context for a notebook. - */ -export async function initNotebookContext( - options: { - path?: string; - manager?: ServiceManager.IManager; - startKernel?: boolean; - } = {} -): Promise> { - const factory = Private.notebookFactory; - const manager = options.manager || Private.getManager(); - const path = options.path || UUID.uuid4() + '.ipynb'; - console.debug( - 'Initializing notebook context for', - path, - 'kernel:', - options.startKernel - ); - - const startKernel = - options.startKernel === undefined ? false : options.startKernel; - await manager.ready; - - const context = new Context({ - manager, - factory, - path, - kernelPreference: { - shouldStart: startKernel, - canStart: startKernel, - shutdownOnDispose: true, - name: manager.kernelspecs.specs?.default - } - }); - await context.initialize(true); - - if (startKernel) { - await context.sessionContext.initialize(); - await context.sessionContext.session?.kernel?.info; - } - - return context; -} - /** * Wait for a dialog to be attached to an element. */ @@ -406,26 +277,3 @@ export async function dismissDialog( simulate(node as HTMLElement, 'keydown', { keyCode: 27 }); } } - -/** - * A namespace for private data. - */ -namespace Private { - let manager: ServiceManager; - - export const textFactory = new TextModelFactory(); - - export const notebookFactory = new NotebookModelFactory({ - disableDocumentWideUndoRedo: false - }); - - /** - * Get or create the service manager singleton. - */ - export function getManager(): ServiceManager { - if (!manager) { - manager = new ServiceManager({ standby: 'never' }); - } - return manager; - } -} diff --git a/packages/shared-models/src/index.ts b/packages/testing/src/index.ts similarity index 50% rename from packages/shared-models/src/index.ts rename to packages/testing/src/index.ts index 1966e16c7b6b..8df54eca9ee1 100644 --- a/packages/shared-models/src/index.ts +++ b/packages/testing/src/index.ts @@ -4,10 +4,22 @@ |----------------------------------------------------------------------------*/ /** * @packageDocumentation - * @module shared-models + * @module testing */ -/** - * @deprecated This package will be removed in JupyterLab 4. Please use @jupyter/ydoc directly - */ -export * from '@jupyter/ydoc'; +export { + testEmission, + expectFailure, + signalToPromises, + signalToPromise, + isFulfilled, + framePromise, + sleep, + waitForDialog, + acceptDialog, + dangerDialog, + dismissDialog, + simulate +} from './common'; + +export { JupyterServer } from './start_jupyter_server'; diff --git a/packages/testing/src/jest-config.ts b/packages/testing/src/jest-config.ts new file mode 100644 index 000000000000..e291a3be8bf1 --- /dev/null +++ b/packages/testing/src/jest-config.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import path from 'path'; + +const esModules = [ + '@codemirror', + '@jupyter/ydoc', + 'lib0', + 'nanoid', + 'vscode-ws-jsonrpc', + 'y-protocols', + 'y-websocket', + 'yjs' +].join('|'); + +module.exports = function (baseDir: string) { + return { + testEnvironment: 'jsdom', + moduleNameMapper: { + '\\.(css|less|sass|scss)$': 'identity-obj-proxy', + '\\.(gif|ttf|eot)$': '@jupyterlab/testing/lib/jest-file-mock.js' + }, + transform: { + '\\.svg$': '@jupyterlab/testing/lib/jest-raw-loader.js', + // Extracted from https://github.com/kulshekhar/ts-jest/blob/v29.0.3/presets/index.js + '^.+\\.tsx?$': [ + 'ts-jest/legacy', + { + tsconfig: `./tsconfig.test.json` + } + ], + '^.+\\.jsx?$': 'babel-jest' + }, + testTimeout: 10000, + setupFiles: ['@jupyterlab/testing/lib/jest-shim.js'], + testPathIgnorePatterns: ['/lib/', '/node_modules/'], + moduleFileExtensions: [ + 'ts', + 'tsx', + 'js', + 'jsx', + 'json', + 'node', + 'mjs', + 'cjs' + ], + transformIgnorePatterns: [`/node_modules/(?!${esModules}).+`], + reporters: ['default', 'jest-junit', 'github-actions'], + coverageReporters: ['json', 'lcov', 'text', 'html'], + coverageDirectory: path.join(baseDir, 'coverage'), + testRegex: '/test/.*.spec.ts[x]?$' + }; +}; diff --git a/packages/testing/src/jest-file-mock.ts b/packages/testing/src/jest-file-mock.ts new file mode 100644 index 000000000000..85c697465da4 --- /dev/null +++ b/packages/testing/src/jest-file-mock.ts @@ -0,0 +1,6 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = 'test-file-stub'; diff --git a/packages/testing/src/jest-raw-loader.ts b/packages/testing/src/jest-raw-loader.ts new file mode 100644 index 000000000000..0ae1cb24eb3c --- /dev/null +++ b/packages/testing/src/jest-raw-loader.ts @@ -0,0 +1,14 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +// jest-raw-loader compatibility with Jest version 28. +// See: https://github.com/keplersj/jest-raw-loader/pull/239 +module.exports = { + process: (content: string): { code: string } => { + return { + code: 'module.exports = ' + JSON.stringify(content) + }; + } +}; diff --git a/testutils/src/jest-shim.ts b/packages/testing/src/jest-shim.ts similarity index 63% rename from testutils/src/jest-shim.ts rename to packages/testing/src/jest-shim.ts index a933cbe96875..1c9cbdc8ae53 100644 --- a/testutils/src/jest-shim.ts +++ b/packages/testing/src/jest-shim.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + // Shims originally adapted from https://github.com/nteract/nteract/blob/47f8b038ff129543e42c39395129efc433eb4e90/scripts/test-shim.js /* global globalThis */ @@ -10,15 +15,28 @@ if ( globalThis.TextEncoder = util.TextEncoder; } -const fetchMod = ((window as any).fetch = require('node-fetch')); // tslint:disable-line +/* global globalThis */ + +globalThis.DragEvent = class DragEvent {} as any; + +if ( + typeof globalThis.TextDecoder === 'undefined' || + typeof globalThis.TextEncoder === 'undefined' +) { + const util = require('util'); + globalThis.TextDecoder = util.TextDecoder; + globalThis.TextEncoder = util.TextEncoder; +} + +const fetchMod = ((window as any).fetch = require('node-fetch')); (window as any).Request = fetchMod.Request; (window as any).Headers = fetchMod.Headers; (window as any).Response = fetchMod.Response; -(global as any).Image = (window as any).Image; -(global as any).Range = function Range() { +globalThis.Image = (window as any).Image; +globalThis.Range = function Range() { /* no-op */ -}; +} as any; // HACK: Polyfill that allows CodeMirror to render in a JSDOM env. const createContextualFragment = (html: string) => { @@ -27,8 +45,8 @@ const createContextualFragment = (html: string) => { return div.children[0]; // so hokey it's not even funny }; -(global as any).Range.prototype.createContextualFragment = (html: string) => - createContextualFragment(html); +globalThis.Range.prototype.createContextualFragment = (html: string) => + createContextualFragment(html) as any; (window as any).document.createRange = function createRange() { return { @@ -39,7 +57,7 @@ const createContextualFragment = (html: string) => { /* no-op */ }, getBoundingClientRect: () => ({ right: 0 }), - getClientRects: (): ClientRect[] => [], + getClientRects: (): DOMRect[] => [], createContextualFragment }; }; @@ -106,3 +124,24 @@ process.on('unhandledRejection', (error, promise) => { } promise.catch(err => console.error('promise rejected', err)); }); + +if ((window as any).requestIdleCallback === undefined) { + // On Safari, requestIdleCallback is not available, so we use replacement functions for `idleCallbacks` + // See: https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API#falling_back_to_settimeout + // eslint-disable-next-line @typescript-eslint/ban-types + (window as any).requestIdleCallback = function (handler: Function) { + let startTime = Date.now(); + return setTimeout(function () { + handler({ + didTimeout: false, + timeRemaining: function () { + return Math.max(0, 50.0 - (Date.now() - startTime)); + } + }); + }, 1); + }; + + (window as any).cancelIdleCallback = function (id: number) { + clearTimeout(id); + }; +} diff --git a/testutils/src/start_jupyter_server.ts b/packages/testing/src/start_jupyter_server.ts similarity index 97% rename from testutils/src/start_jupyter_server.ts rename to packages/testing/src/start_jupyter_server.ts index 5a6f8b21ba05..908d74303b28 100644 --- a/testutils/src/start_jupyter_server.ts +++ b/packages/testing/src/start_jupyter_server.ts @@ -1,3 +1,9 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +/* eslint-disable camelcase */ // Copyright (c) Jupyter Development Team. import { ChildProcess, spawn } from 'child_process'; @@ -24,7 +30,7 @@ import { sleep } from './common'; * * beforeAll(async () => { * await server.start(); - * }); + * }, 30000); * * afterAll(async () => { * await server.shutdown(); @@ -160,6 +166,7 @@ namespace Private { /** * Install a spec in the data directory. */ + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function installSpec(dataDir: string, name: string, spec: any): void { const specDir = path.join(dataDir, 'kernels', name); fs.mkdirSync(specDir, { recursive: true }); diff --git a/testutils/test/start_jupyter_server.spec.ts b/packages/testing/test/start_jupyter_server.spec.ts similarity index 85% rename from testutils/test/start_jupyter_server.spec.ts rename to packages/testing/test/start_jupyter_server.spec.ts index d2214cc145bd..49ac88dc56a8 100644 --- a/testutils/test/start_jupyter_server.spec.ts +++ b/packages/testing/test/start_jupyter_server.spec.ts @@ -3,25 +3,26 @@ const fetch = require('node-fetch'); -import { JupyterServer } from '../src'; import { PageConfig, URLExt } from '@jupyterlab/coreutils'; +import { JupyterServer } from '@jupyterlab/testing'; describe('JupyterServer', () => { it('should start the server', async () => { - jest.setTimeout(20000); const server = new JupyterServer(); const url = await server.start(); await fetch(URLExt.join(url, 'api')); - await server.shutdown(); - }); + await expect(server.shutdown()).resolves.not.toThrow(); + }, 30000); it('should accept options', async () => { - jest.setTimeout(20000); const pageConfig = { foo: 'bar', fizz: 'buzz' }; const configData = { + // eslint-disable-next-line camelcase FakeTrait: { fake_prop: 1 }, + // eslint-disable-next-line camelcase OtherTrait: { other_prop: 'hello' }, KernelManager: { + // eslint-disable-next-line camelcase shutdown_wait_time: 1.11 } }; @@ -46,5 +47,5 @@ describe('JupyterServer', () => { expect(PageConfig.getOption('__configData')).toContain('1.11'); expect(PageConfig.getOption('__kernelSpec_foo')).toContain('Test Python'); await expect(server.shutdown()).resolves.not.toThrow(); - }); + }, 30000); }); diff --git a/packages/shared-models/tsconfig.json b/packages/testing/tsconfig.json similarity index 59% rename from packages/shared-models/tsconfig.json rename to packages/testing/tsconfig.json index a26281b11a8f..2148e288c01e 100644 --- a/packages/shared-models/tsconfig.json +++ b/packages/testing/tsconfig.json @@ -2,12 +2,14 @@ "extends": "../../tsconfigbase", "compilerOptions": { "outDir": "lib", - "rootDir": "src" + "rootDir": "src", + "module": "commonjs", + "types": ["node"] }, "include": ["src/*"], "references": [ { - "path": "../nbformat" + "path": "../coreutils" } ] } diff --git a/packages/testing/tsconfig.test.json b/packages/testing/tsconfig.test.json new file mode 100644 index 000000000000..576dab4f5622 --- /dev/null +++ b/packages/testing/tsconfig.test.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfigbase.test", + "include": ["src/*", "test/*"], + "references": [ + { + "path": "../coreutils" + }, + { + "path": "." + } + ] +} diff --git a/packages/theme-dark-extension/package.json b/packages/theme-dark-extension/package.json index f1773b4339d1..9912cde855d5 100644 --- a/packages/theme-dark-extension/package.json +++ b/packages/theme-dark-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/theme-dark-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Default Dark Theme", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -23,7 +23,8 @@ "lib/*.js.map", "lib/*.js", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -31,14 +32,14 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/translation": "^3.6.6" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/translation": "^4.0.8" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/theme-dark-extension/src/index.ts b/packages/theme-dark-extension/src/index.ts index 6f20ea8e9a02..20d7effc075c 100644 --- a/packages/theme-dark-extension/src/index.ts +++ b/packages/theme-dark-extension/src/index.ts @@ -17,6 +17,7 @@ import { ITranslator } from '@jupyterlab/translation'; */ const plugin: JupyterFrontEndPlugin = { id: '@jupyterlab/theme-dark-extension:plugin', + description: 'Adds a dark theme.', requires: [IThemeManager, ITranslator], activate: ( app: JupyterFrontEnd, diff --git a/packages/theme-dark-extension/style/theme.css b/packages/theme-dark-extension/style/theme.css index 594e597834d9..dece106611b3 100644 --- a/packages/theme-dark-extension/style/theme.css +++ b/packages/theme-dark-extension/style/theme.css @@ -17,8 +17,10 @@ pre { } /* fix illegible yellow backround in exception stacktrace */ -:where(.jp-RenderedText[data-mime-type='application/vnd.jupyter.stderr'] - pre - .ansi-yellow-bg) { +:where( + .jp-RenderedText[data-mime-type='application/vnd.jupyter.stderr'] + pre + .ansi-yellow-bg + ) { color: black; } diff --git a/packages/theme-dark-extension/style/variables.css b/packages/theme-dark-extension/style/variables.css index b9eeb8eea481..5f06654010dd 100644 --- a/packages/theme-dark-extension/style/variables.css +++ b/packages/theme-dark-extension/style/variables.css @@ -55,33 +55,33 @@ all of MD as it is not optimized for dense, information rich UIs. 0.12 ); --jp-elevation-z0: none; - --jp-elevation-z1: 0px 2px 1px -1px var(--jp-shadow-umbra-color), - 0px 1px 1px 0px var(--jp-shadow-penumbra-color), - 0px 1px 3px 0px var(--jp-shadow-ambient-color); - --jp-elevation-z2: 0px 3px 1px -2px var(--jp-shadow-umbra-color), - 0px 2px 2px 0px var(--jp-shadow-penumbra-color), - 0px 1px 5px 0px var(--jp-shadow-ambient-color); - --jp-elevation-z4: 0px 2px 4px -1px var(--jp-shadow-umbra-color), - 0px 4px 5px 0px var(--jp-shadow-penumbra-color), - 0px 1px 10px 0px var(--jp-shadow-ambient-color); - --jp-elevation-z6: 0px 3px 5px -1px var(--jp-shadow-umbra-color), - 0px 6px 10px 0px var(--jp-shadow-penumbra-color), - 0px 1px 18px 0px var(--jp-shadow-ambient-color); - --jp-elevation-z8: 0px 5px 5px -3px var(--jp-shadow-umbra-color), - 0px 8px 10px 1px var(--jp-shadow-penumbra-color), - 0px 3px 14px 2px var(--jp-shadow-ambient-color); - --jp-elevation-z12: 0px 7px 8px -4px var(--jp-shadow-umbra-color), - 0px 12px 17px 2px var(--jp-shadow-penumbra-color), - 0px 5px 22px 4px var(--jp-shadow-ambient-color); - --jp-elevation-z16: 0px 8px 10px -5px var(--jp-shadow-umbra-color), - 0px 16px 24px 2px var(--jp-shadow-penumbra-color), - 0px 6px 30px 5px var(--jp-shadow-ambient-color); - --jp-elevation-z20: 0px 10px 13px -6px var(--jp-shadow-umbra-color), - 0px 20px 31px 3px var(--jp-shadow-penumbra-color), - 0px 8px 38px 7px var(--jp-shadow-ambient-color); - --jp-elevation-z24: 0px 11px 15px -7px var(--jp-shadow-umbra-color), - 0px 24px 38px 3px var(--jp-shadow-penumbra-color), - 0px 9px 46px 8px var(--jp-shadow-ambient-color); + --jp-elevation-z1: 0 2px 1px -1px var(--jp-shadow-umbra-color), + 0 1px 1px 0 var(--jp-shadow-penumbra-color), + 0 1px 3px 0 var(--jp-shadow-ambient-color); + --jp-elevation-z2: 0 3px 1px -2px var(--jp-shadow-umbra-color), + 0 2px 2px 0 var(--jp-shadow-penumbra-color), + 0 1px 5px 0 var(--jp-shadow-ambient-color); + --jp-elevation-z4: 0 2px 4px -1px var(--jp-shadow-umbra-color), + 0 4px 5px 0 var(--jp-shadow-penumbra-color), + 0 1px 10px 0 var(--jp-shadow-ambient-color); + --jp-elevation-z6: 0 3px 5px -1px var(--jp-shadow-umbra-color), + 0 6px 10px 0 var(--jp-shadow-penumbra-color), + 0 1px 18px 0 var(--jp-shadow-ambient-color); + --jp-elevation-z8: 0 5px 5px -3px var(--jp-shadow-umbra-color), + 0 8px 10px 1px var(--jp-shadow-penumbra-color), + 0 3px 14px 2px var(--jp-shadow-ambient-color); + --jp-elevation-z12: 0 7px 8px -4px var(--jp-shadow-umbra-color), + 0 12px 17px 2px var(--jp-shadow-penumbra-color), + 0 5px 22px 4px var(--jp-shadow-ambient-color); + --jp-elevation-z16: 0 8px 10px -5px var(--jp-shadow-umbra-color), + 0 16px 24px 2px var(--jp-shadow-penumbra-color), + 0 6px 30px 5px var(--jp-shadow-ambient-color); + --jp-elevation-z20: 0 10px 13px -6px var(--jp-shadow-umbra-color), + 0 20px 31px 3px var(--jp-shadow-penumbra-color), + 0 8px 38px 7px var(--jp-shadow-ambient-color); + --jp-elevation-z24: 0 11px 15px -7px var(--jp-shadow-umbra-color), + 0 24px 38px 3px var(--jp-shadow-penumbra-color), + 0 9px 46px 8px var(--jp-shadow-ambient-color); /* Borders * @@ -111,9 +111,9 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-ui-font-size1: 13px; /* Base font size */ --jp-ui-font-size2: 1.2em; --jp-ui-font-size3: 1.44em; - - --jp-ui-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, - Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + --jp-ui-font-family: system-ui, -apple-system, blinkmacsystemfont, 'Segoe UI', + helvetica, arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol'; /* * Use these font colors against the corresponding main layout colors. @@ -156,7 +156,6 @@ all of MD as it is not optimized for dense, information rich UIs. /* This gives a magnification of about 125% in presentation mode over normal. */ --jp-content-presentation-font-size1: 17px; - --jp-content-heading-line-height: 1; --jp-content-heading-margin-top: 1.2em; --jp-content-heading-margin-bottom: 0.8em; @@ -167,12 +166,10 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-content-font-color1: rgba(255, 255, 255, 1); --jp-content-font-color2: rgba(255, 255, 255, 0.7); --jp-content-font-color3: rgba(255, 255, 255, 0.5); - --jp-content-link-color: var(--md-blue-300); - - --jp-content-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', - Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol'; + --jp-content-font-family: system-ui, -apple-system, blinkmacsystemfont, + 'Segoe UI', helvetica, arial, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol'; /* * Code Fonts @@ -183,7 +180,7 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-code-font-size: 13px; --jp-code-line-height: 1.3077; /* 17px for 13px base */ --jp-code-padding: 5px; /* 5px for 13px base, codemirror highlighting needs integer px value */ - --jp-code-font-family-default: Menlo, Consolas, 'DejaVu Sans Mono', monospace; + --jp-code-font-family-default: menlo, consolas, 'DejaVu Sans Mono', monospace; --jp-code-font-family: var(--jp-code-font-family-default); /* This gives a magnification of about 125% in presentation mode over normal. */ @@ -200,7 +197,7 @@ all of MD as it is not optimized for dense, information rich UIs. * theme these would go from light to dark. */ - --jp-layout-color0: #111111; + --jp-layout-color0: #111; --jp-layout-color1: var(--md-grey-900); --jp-layout-color2: var(--md-grey-800); --jp-layout-color3: var(--md-grey-700); @@ -225,7 +222,6 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-brand-color2: var(--md-blue-300); --jp-brand-color3: var(--md-blue-100); --jp-brand-color4: var(--md-blue-50); - --jp-accent-color0: var(--md-green-700); --jp-accent-color1: var(--md-green-500); --jp-accent-color2: var(--md-green-300); @@ -237,17 +233,14 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-warn-color1: var(--md-orange-500); --jp-warn-color2: var(--md-orange-300); --jp-warn-color3: var(--md-orange-100); - --jp-error-color0: var(--md-red-700); --jp-error-color1: var(--md-red-500); --jp-error-color2: var(--md-red-300); --jp-error-color3: var(--md-red-100); - --jp-success-color0: var(--md-green-700); --jp-success-color1: var(--md-green-500); --jp-success-color2: var(--md-green-300); --jp-success-color3: var(--md-green-100); - --jp-info-color0: var(--md-cyan-700); --jp-info-color1: var(--md-cyan-500); --jp-info-color2: var(--md-cyan-300); @@ -256,20 +249,17 @@ all of MD as it is not optimized for dense, information rich UIs. /* Cell specific styles */ --jp-cell-padding: 5px; - --jp-cell-collapser-width: 8px; --jp-cell-collapser-min-height: 20px; --jp-cell-collapser-not-active-hover-opacity: 0.6; - --jp-cell-editor-background: var(--jp-layout-color1); --jp-cell-editor-border-color: var(--md-grey-700); --jp-cell-editor-box-shadow: inset 0 0 2px var(--md-blue-300); --jp-cell-editor-active-background: var(--jp-layout-color0); --jp-cell-editor-active-border-color: var(--jp-brand-color1); - --jp-cell-prompt-width: 64px; --jp-cell-prompt-font-family: var(--jp-code-font-family-default); - --jp-cell-prompt-letter-spacing: 0px; + --jp-cell-prompt-letter-spacing: 0; --jp-cell-prompt-opacity: 1; --jp-cell-prompt-not-active-opacity: 1; --jp-cell-prompt-not-active-font-color: var(--md-grey-300); @@ -277,6 +267,7 @@ all of MD as it is not optimized for dense, information rich UIs. /* A custom blend of MD grey and blue 600 * See https://meyerweb.com/eric/tools/color-blend/#546E7A:1E88E5:5:hex */ --jp-cell-inprompt-font-color: #307fc1; + /* A custom blend of MD grey and orange 600 * https://meyerweb.com/eric/tools/color-blend/#546E7A:F4511E:5:hex */ --jp-cell-outprompt-font-color: #bf5b3d; @@ -317,8 +308,8 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-toolbar-border-color: var(--jp-border-color2); --jp-toolbar-micro-height: 8px; --jp-toolbar-background: var(--jp-layout-color1); - --jp-toolbar-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.8); - --jp-toolbar-header-margin: 4px 4px 0px 4px; + --jp-toolbar-box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.8); + --jp-toolbar-header-margin: 4px 4px 0 4px; --jp-toolbar-active-background: var(--jp-layout-color0); /* Statusbar specific styles */ @@ -348,15 +339,15 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-mirror-editor-number-color: var(--md-green-400); --jp-mirror-editor-def-color: var(--md-blue-600); --jp-mirror-editor-variable-color: var(--md-grey-300); - --jp-mirror-editor-variable-2-color: var(--md-blue-400); + --jp-mirror-editor-variable-2-color: var(--md-blue-500); --jp-mirror-editor-variable-3-color: var(--md-green-600); --jp-mirror-editor-punctuation-color: var(--md-blue-400); --jp-mirror-editor-property-color: var(--md-blue-400); - --jp-mirror-editor-operator-color: #aa22ff; + --jp-mirror-editor-operator-color: #a2f; --jp-mirror-editor-comment-color: #408080; --jp-mirror-editor-string-color: #ff7070; --jp-mirror-editor-string-2-color: var(--md-purple-300); - --jp-mirror-editor-meta-color: #aa22ff; + --jp-mirror-editor-meta-color: #a2f; --jp-mirror-editor-qualifier-color: #555; --jp-mirror-editor-builtin-color: var(--md-green-600); --jp-mirror-editor-bracket-color: #997; @@ -408,7 +399,6 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-scrollbar-background-color: #3f4244; --jp-scrollbar-thumb-color: 88, 96, 97; /* need to specify thumb color as an RGB triplet */ - --jp-scrollbar-endpad: 3px; /* the minimum gap between the thumb and the ends of a scrollbar */ /* hacks for setting the thumb shape. These do nothing in Firefox */ @@ -422,6 +412,17 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-icon-contrast-color2: var(--md-pink-600); --jp-icon-contrast-color3: var(--md-blue-600); + /* Button colors */ + --jp-accept-color-normal: var(--md-blue-700); + --jp-accept-color-hover: var(--md-blue-800); + --jp-accept-color-active: var(--md-blue-900); + --jp-warn-color-normal: var(--md-red-700); + --jp-warn-color-hover: var(--md-red-800); + --jp-warn-color-active: var(--md-red-900); + --jp-reject-color-normal: var(--md-grey-600); + --jp-reject-color-hover: var(--md-grey-700); + --jp-reject-color-active: var(--md-grey-800); + /* File or activity icons and switch semantic variables */ --jp-jupyter-icon-color: #f37626; --jp-notebook-icon-color: #f37626; diff --git a/packages/theme-light-extension/package.json b/packages/theme-light-extension/package.json index 0b3d436ddab2..f078533d26c4 100644 --- a/packages/theme-light-extension/package.json +++ b/packages/theme-light-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/theme-light-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Default Light Theme", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -23,7 +23,8 @@ "lib/*.js.map", "lib/*.js", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -31,14 +32,14 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/translation": "^3.6.6" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/translation": "^4.0.8" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/theme-light-extension/src/index.ts b/packages/theme-light-extension/src/index.ts index 7b05195b6612..8f404b2e9d41 100644 --- a/packages/theme-light-extension/src/index.ts +++ b/packages/theme-light-extension/src/index.ts @@ -17,6 +17,7 @@ import { ITranslator } from '@jupyterlab/translation'; */ const plugin: JupyterFrontEndPlugin = { id: '@jupyterlab/theme-light-extension:plugin', + description: 'Adds a light theme.', requires: [IThemeManager, ITranslator], activate: ( app: JupyterFrontEnd, diff --git a/packages/theme-light-extension/style/urls.css b/packages/theme-light-extension/style/urls.css index b657e4d0df13..df17792b0749 100644 --- a/packages/theme-light-extension/style/urls.css +++ b/packages/theme-light-extension/style/urls.css @@ -12,9 +12,14 @@ /* blocked by lumino interaction */ /*--jp-icon-caret-down: url('icons/md/caretdown.svg');*/ + /*--jp-icon-caret-right: url('icons/md/caretright.svg');*/ + /*--jp-icon-caret-up: url('icons/md/caretup.svg');*/ + /*--jp-icon-caret-left: url('icons/md/caretleft.svg');*/ + /*--jp-icon-search: url('icons/md/search.svg');*/ + /*--jp-icon-search-white: url('icons/md/search-white.svg');*/ } diff --git a/packages/theme-light-extension/style/variables.css b/packages/theme-light-extension/style/variables.css index b3fc9b79f5ad..b3ae305d6c9f 100644 --- a/packages/theme-light-extension/style/variables.css +++ b/packages/theme-light-extension/style/variables.css @@ -53,33 +53,33 @@ all of MD as it is not optimized for dense, information rich UIs. 0.12 ); --jp-elevation-z0: none; - --jp-elevation-z1: 0px 2px 1px -1px var(--jp-shadow-umbra-color), - 0px 1px 1px 0px var(--jp-shadow-penumbra-color), - 0px 1px 3px 0px var(--jp-shadow-ambient-color); - --jp-elevation-z2: 0px 3px 1px -2px var(--jp-shadow-umbra-color), - 0px 2px 2px 0px var(--jp-shadow-penumbra-color), - 0px 1px 5px 0px var(--jp-shadow-ambient-color); - --jp-elevation-z4: 0px 2px 4px -1px var(--jp-shadow-umbra-color), - 0px 4px 5px 0px var(--jp-shadow-penumbra-color), - 0px 1px 10px 0px var(--jp-shadow-ambient-color); - --jp-elevation-z6: 0px 3px 5px -1px var(--jp-shadow-umbra-color), - 0px 6px 10px 0px var(--jp-shadow-penumbra-color), - 0px 1px 18px 0px var(--jp-shadow-ambient-color); - --jp-elevation-z8: 0px 5px 5px -3px var(--jp-shadow-umbra-color), - 0px 8px 10px 1px var(--jp-shadow-penumbra-color), - 0px 3px 14px 2px var(--jp-shadow-ambient-color); - --jp-elevation-z12: 0px 7px 8px -4px var(--jp-shadow-umbra-color), - 0px 12px 17px 2px var(--jp-shadow-penumbra-color), - 0px 5px 22px 4px var(--jp-shadow-ambient-color); - --jp-elevation-z16: 0px 8px 10px -5px var(--jp-shadow-umbra-color), - 0px 16px 24px 2px var(--jp-shadow-penumbra-color), - 0px 6px 30px 5px var(--jp-shadow-ambient-color); - --jp-elevation-z20: 0px 10px 13px -6px var(--jp-shadow-umbra-color), - 0px 20px 31px 3px var(--jp-shadow-penumbra-color), - 0px 8px 38px 7px var(--jp-shadow-ambient-color); - --jp-elevation-z24: 0px 11px 15px -7px var(--jp-shadow-umbra-color), - 0px 24px 38px 3px var(--jp-shadow-penumbra-color), - 0px 9px 46px 8px var(--jp-shadow-ambient-color); + --jp-elevation-z1: 0 2px 1px -1px var(--jp-shadow-umbra-color), + 0 1px 1px 0 var(--jp-shadow-penumbra-color), + 0 1px 3px 0 var(--jp-shadow-ambient-color); + --jp-elevation-z2: 0 3px 1px -2px var(--jp-shadow-umbra-color), + 0 2px 2px 0 var(--jp-shadow-penumbra-color), + 0 1px 5px 0 var(--jp-shadow-ambient-color); + --jp-elevation-z4: 0 2px 4px -1px var(--jp-shadow-umbra-color), + 0 4px 5px 0 var(--jp-shadow-penumbra-color), + 0 1px 10px 0 var(--jp-shadow-ambient-color); + --jp-elevation-z6: 0 3px 5px -1px var(--jp-shadow-umbra-color), + 0 6px 10px 0 var(--jp-shadow-penumbra-color), + 0 1px 18px 0 var(--jp-shadow-ambient-color); + --jp-elevation-z8: 0 5px 5px -3px var(--jp-shadow-umbra-color), + 0 8px 10px 1px var(--jp-shadow-penumbra-color), + 0 3px 14px 2px var(--jp-shadow-ambient-color); + --jp-elevation-z12: 0 7px 8px -4px var(--jp-shadow-umbra-color), + 0 12px 17px 2px var(--jp-shadow-penumbra-color), + 0 5px 22px 4px var(--jp-shadow-ambient-color); + --jp-elevation-z16: 0 8px 10px -5px var(--jp-shadow-umbra-color), + 0 16px 24px 2px var(--jp-shadow-penumbra-color), + 0 6px 30px 5px var(--jp-shadow-ambient-color); + --jp-elevation-z20: 0 10px 13px -6px var(--jp-shadow-umbra-color), + 0 20px 31px 3px var(--jp-shadow-penumbra-color), + 0 8px 38px 7px var(--jp-shadow-ambient-color); + --jp-elevation-z24: 0 11px 15px -7px var(--jp-shadow-umbra-color), + 0 24px 38px 3px var(--jp-shadow-penumbra-color), + 0 9px 46px 8px var(--jp-shadow-ambient-color); /* Borders * @@ -109,9 +109,9 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-ui-font-size1: 13px; /* Base font size */ --jp-ui-font-size2: 1.2em; --jp-ui-font-size3: 1.44em; - - --jp-ui-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, - Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + --jp-ui-font-family: system-ui, -apple-system, blinkmacsystemfont, 'Segoe UI', + helvetica, arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol'; /* * Use these font colors against the corresponding main layout colors. @@ -154,7 +154,6 @@ all of MD as it is not optimized for dense, information rich UIs. /* This gives a magnification of about 125% in presentation mode over normal. */ --jp-content-presentation-font-size1: 17px; - --jp-content-heading-line-height: 1; --jp-content-heading-margin-top: 1.2em; --jp-content-heading-margin-bottom: 0.8em; @@ -165,12 +164,10 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-content-font-color1: rgba(0, 0, 0, 0.87); --jp-content-font-color2: rgba(0, 0, 0, 0.54); --jp-content-font-color3: rgba(0, 0, 0, 0.38); - - --jp-content-link-color: var(--md-blue-700); - - --jp-content-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', - Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol'; + --jp-content-link-color: var(--md-blue-900); + --jp-content-font-family: system-ui, -apple-system, blinkmacsystemfont, + 'Segoe UI', helvetica, arial, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol'; /* * Code Fonts @@ -181,7 +178,7 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-code-font-size: 13px; --jp-code-line-height: 1.3077; /* 17px for 13px base */ --jp-code-padding: 5px; /* 5px for 13px base, codemirror highlighting needs integer px value */ - --jp-code-font-family-default: Menlo, Consolas, 'DejaVu Sans Mono', monospace; + --jp-code-font-family-default: menlo, consolas, 'DejaVu Sans Mono', monospace; --jp-code-font-family: var(--jp-code-font-family-default); /* This gives a magnification of about 125% in presentation mode over normal. */ @@ -210,7 +207,7 @@ all of MD as it is not optimized for dense, information rich UIs. * theme these would go from dark to light. */ - --jp-inverse-layout-color0: #111111; + --jp-inverse-layout-color0: #111; --jp-inverse-layout-color1: var(--md-grey-900); --jp-inverse-layout-color2: var(--md-grey-800); --jp-inverse-layout-color3: var(--md-grey-700); @@ -223,7 +220,6 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-brand-color2: var(--md-blue-300); --jp-brand-color3: var(--md-blue-100); --jp-brand-color4: var(--md-blue-50); - --jp-accent-color0: var(--md-green-900); --jp-accent-color1: var(--md-green-700); --jp-accent-color2: var(--md-green-300); @@ -235,17 +231,14 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-warn-color1: var(--md-orange-700); --jp-warn-color2: var(--md-orange-300); --jp-warn-color3: var(--md-orange-100); - --jp-error-color0: var(--md-red-900); --jp-error-color1: var(--md-red-700); --jp-error-color2: var(--md-red-300); --jp-error-color3: var(--md-red-100); - --jp-success-color0: var(--md-green-900); --jp-success-color1: var(--md-green-700); --jp-success-color2: var(--md-green-300); --jp-success-color3: var(--md-green-100); - --jp-info-color0: var(--md-cyan-900); --jp-info-color1: var(--md-cyan-700); --jp-info-color2: var(--md-cyan-300); @@ -254,26 +247,25 @@ all of MD as it is not optimized for dense, information rich UIs. /* Cell specific styles */ --jp-cell-padding: 5px; - --jp-cell-collapser-width: 8px; --jp-cell-collapser-min-height: 20px; --jp-cell-collapser-not-active-hover-opacity: 0.6; - --jp-cell-editor-background: var(--md-grey-100); --jp-cell-editor-border-color: var(--md-grey-300); --jp-cell-editor-box-shadow: inset 0 0 2px var(--md-blue-300); --jp-cell-editor-active-background: var(--jp-layout-color0); --jp-cell-editor-active-border-color: var(--jp-brand-color1); - --jp-cell-prompt-width: 64px; --jp-cell-prompt-font-family: var(--jp-code-font-family-default); - --jp-cell-prompt-letter-spacing: 0px; + --jp-cell-prompt-letter-spacing: 0; --jp-cell-prompt-opacity: 1; --jp-cell-prompt-not-active-opacity: 0.5; --jp-cell-prompt-not-active-font-color: var(--md-grey-700); + /* A custom blend of MD grey and blue 600 * See https://meyerweb.com/eric/tools/color-blend/#546E7A:1E88E5:5:hex */ --jp-cell-inprompt-font-color: #307fc1; + /* A custom blend of MD grey and orange 600 * https://meyerweb.com/eric/tools/color-blend/#546E7A:F4511E:5:hex */ --jp-cell-outprompt-font-color: #bf5b3d; @@ -314,8 +306,8 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-toolbar-border-color: var(--jp-border-color1); --jp-toolbar-micro-height: 8px; --jp-toolbar-background: var(--jp-layout-color1); - --jp-toolbar-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.24); - --jp-toolbar-header-margin: 4px 4px 0px 4px; + --jp-toolbar-box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.24); + --jp-toolbar-header-margin: 4px 4px 0 4px; --jp-toolbar-active-background: var(--md-grey-300); /* Statusbar specific styles */ @@ -345,15 +337,15 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-mirror-editor-number-color: #080; --jp-mirror-editor-def-color: #00f; --jp-mirror-editor-variable-color: var(--md-grey-900); - --jp-mirror-editor-variable-2-color: #05a; + --jp-mirror-editor-variable-2-color: rgb(0, 54, 109); --jp-mirror-editor-variable-3-color: #085; --jp-mirror-editor-punctuation-color: #05a; --jp-mirror-editor-property-color: #05a; - --jp-mirror-editor-operator-color: #aa22ff; + --jp-mirror-editor-operator-color: #a2f; --jp-mirror-editor-comment-color: #408080; --jp-mirror-editor-string-color: #ba2121; --jp-mirror-editor-string-2-color: #708; - --jp-mirror-editor-meta-color: #aa22ff; + --jp-mirror-editor-meta-color: #a2f; --jp-mirror-editor-qualifier-color: #555; --jp-mirror-editor-builtin-color: #008000; --jp-mirror-editor-bracket-color: #997; @@ -405,6 +397,17 @@ all of MD as it is not optimized for dense, information rich UIs. --jp-icon-contrast-color2: var(--md-pink-600); --jp-icon-contrast-color3: var(--md-blue-600); + /* Button colors */ + --jp-accept-color-normal: var(--md-blue-700); + --jp-accept-color-hover: var(--md-blue-800); + --jp-accept-color-active: var(--md-blue-900); + --jp-warn-color-normal: var(--md-red-700); + --jp-warn-color-hover: var(--md-red-800); + --jp-warn-color-active: var(--md-red-900); + --jp-reject-color-normal: var(--md-grey-600); + --jp-reject-color-hover: var(--md-grey-700); + --jp-reject-color-active: var(--md-grey-800); + /* File or activity icons and switch semantic variables */ --jp-jupyter-icon-color: #f37626; --jp-notebook-icon-color: #f37626; diff --git a/packages/toc-extension/package.json b/packages/toc-extension/package.json index a9a58df4d6b7..c8a49b32fa9e 100644 --- a/packages/toc-extension/package.json +++ b/packages/toc-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/toc-extension", - "version": "5.6.6", + "version": "6.0.8", "description": "JupyterLab - Table of Contents widget extension", "keywords": [ "jupyter", @@ -29,9 +29,10 @@ }, "files": [ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", + "schema/*.json", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", "style/index.js", - "schema/*.json" + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -40,22 +41,16 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/cells": "^3.6.6", - "@jupyterlab/docmanager": "^3.6.6", - "@jupyterlab/fileeditor": "^3.6.6", - "@jupyterlab/markdownviewer": "^3.6.6", - "@jupyterlab/notebook": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/toc": "^5.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@jupyterlab/toc": "^6.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/toc-extension/schema/plugin.json b/packages/toc-extension/schema/plugin.json deleted file mode 100644 index e249d1313126..000000000000 --- a/packages/toc-extension/schema/plugin.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "jupyter.lab.setting-icon": "ui-components:toc", - "jupyter.lab.setting-icon-label": "Table of Contents", - "title": "Table of Contents", - "description": "Table of contents settings.", - "jupyter.lab.menus": { - "context": [ - { - "command": "toc:run-cells", - "selector": ".jp-tocItem" - } - ] - }, - "properties": { - "numberingH1": { - "title": "Enable h1 numbering", - "description": "Whether to number first-level headings", - "type": "boolean", - "default": true - }, - "includeOutput": { - "title": "Include cell output in headings", - "description": "Whether to include cell output in headings", - "type": "boolean", - "default": true - }, - "syncCollapseState": { - "type": "boolean", - "title": "Synchronize collapse state", - "description": "If set to true, when a header is collapsed in the table of contents the corresponding section in the notebook is collapsed as well and vice versa.", - "default": false - } - }, - "additionalProperties": false, - "type": "object" -} diff --git a/packages/toc-extension/schema/registry.json b/packages/toc-extension/schema/registry.json new file mode 100644 index 000000000000..aeb56c458259 --- /dev/null +++ b/packages/toc-extension/schema/registry.json @@ -0,0 +1,72 @@ +{ + "jupyter.lab.setting-icon": "ui-components:toc", + "jupyter.lab.setting-icon-label": "Table of Contents", + "title": "Table of Contents", + "description": "Default table of contents settings.", + "jupyter.lab.menus": { + "main": [ + { + "id": "jp-mainmenu-view", + "items": [ + { + "command": "toc:show-panel", + "rank": 4 + } + ] + } + ], + "context": [ + { + "command": "toc:run-cells", + "selector": ".jp-TableOfContents-content[data-document-type=\"notebook\"] .jp-tocItem" + } + ] + }, + "jupyter.lab.shortcuts": [ + { + "command": "toc:show-panel", + "keys": ["Accel Shift K"], + "selector": "body" + } + ], + "properties": { + "maximalDepth": { + "title": "Maximal headings depth", + "type": "integer", + "minimum": 1, + "default": 4 + }, + "numberingH1": { + "title": "Enable 1st headings numbering", + "description": "Whether to number first-level headings or not.", + "type": "boolean", + "default": true + }, + "numberHeaders": { + "title": "Enable headings numbering", + "description": "Whether to automatically number the headings or not.", + "type": "boolean", + "default": false + }, + "includeOutput": { + "title": "Include cell output in headings", + "description": "Whether to include cell output in headings or not.", + "type": "boolean", + "default": true + }, + "syncCollapseState": { + "type": "boolean", + "title": "Synchronize collapse state", + "description": "If set to true, when a heading is collapsed in the table of contents the corresponding section in the document is collapsed as well and vice versa. This inhibits the cell output headings.", + "default": false + }, + "baseNumbering": { + "title": "Base level for the highest headings", + "type": "integer", + "description": "The number headings start at.", + "default": 1 + } + }, + "additionalProperties": false, + "type": "object" +} diff --git a/packages/toc-extension/src/index.ts b/packages/toc-extension/src/index.ts index 334a5a2a2dcc..e0e9e69af392 100644 --- a/packages/toc-extension/src/index.ts +++ b/packages/toc-extension/src/index.ts @@ -11,32 +11,41 @@ import { JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; -import { IDocumentManager } from '@jupyterlab/docmanager'; -import { IEditorTracker } from '@jupyterlab/fileeditor'; -import { IMarkdownViewerTracker } from '@jupyterlab/markdownviewer'; -import { INotebookTracker } from '@jupyterlab/notebook'; -import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { - createLatexGenerator, - createMarkdownGenerator, - createNotebookGenerator, - createPythonGenerator, - createRenderedMarkdownGenerator, ITableOfContentsRegistry, - TableOfContentsRegistry as Registry, - TableOfContents + ITableOfContentsTracker, + TableOfContents, + TableOfContentsPanel, + TableOfContentsRegistry, + TableOfContentsTracker } from '@jupyterlab/toc'; -import { ITranslator } from '@jupyterlab/translation'; -import { tocIcon } from '@jupyterlab/ui-components'; -import { INotebookHeading } from '@jupyterlab/toc'; -import { CodeCell, MarkdownCell } from '@jupyterlab/cells'; +import { ITranslator, nullTranslator } from '@jupyterlab/translation'; +import { + collapseAllIcon, + CommandToolbarButton, + ellipsesIcon, + expandAllIcon, + MenuSvg, + numberingIcon, + tocIcon, + Toolbar, + ToolbarButton +} from '@jupyterlab/ui-components'; /** - * The command IDs used by TOC item. + * A namespace for command IDs of table of contents plugin. */ namespace CommandIDs { - export const runCells = 'toc:run-cells'; + export const displayNumbering = 'toc:display-numbering'; + + export const displayH1Numbering = 'toc:display-h1-numbering'; + + export const displayOutputNumbering = 'toc:display-outputs-numbering'; + + export const showPanel = 'toc:show-panel'; + + export const toggleCollapse = 'toc:toggle-collapse'; } /** @@ -44,91 +53,112 @@ namespace CommandIDs { * * @private * @param app - Jupyter application - * @param docmanager - document manager - * @param rendermime - rendered MIME registry + * @param tocRegistry - Table of contents registry * @param translator - translator - * @param editorTracker - editor tracker * @param restorer - application layout restorer * @param labShell - Jupyter lab shell - * @param markdownViewerTracker - Markdown viewer tracker - * @param notebookTracker - notebook tracker * @param settingRegistry - setting registry * @returns table of contents registry */ async function activateTOC( app: JupyterFrontEnd, - docmanager: IDocumentManager, - rendermime: IRenderMimeRegistry, - translator: ITranslator, - editorTracker?: IEditorTracker, - restorer?: ILayoutRestorer, - labShell?: ILabShell, - markdownViewerTracker?: IMarkdownViewerTracker, - notebookTracker?: INotebookTracker, - settingRegistry?: ISettingRegistry -): Promise { - const trans = translator.load('jupyterlab'); - // Create the ToC widget: - const toc = new TableOfContents({ - docmanager, - rendermime, - translator - }); + tocRegistry: ITableOfContentsRegistry, + translator?: ITranslator | null, + restorer?: ILayoutRestorer | null, + labShell?: ILabShell | null, + settingRegistry?: ISettingRegistry | null +): Promise { + const trans = (translator ?? nullTranslator).load('jupyterlab'); + let configuration = { ...TableOfContents.defaultConfig }; - // Create the ToC registry: - const registry = new Registry(); - - // Add the ToC to the left area: + // Create the ToC widget: + const toc = new TableOfContentsPanel(translator ?? undefined); toc.title.icon = tocIcon; toc.title.caption = trans.__('Table of Contents'); toc.id = 'table-of-contents'; toc.node.setAttribute('role', 'region'); toc.node.setAttribute('aria-label', trans.__('Table of Contents section')); - app.shell.add(toc, 'left', { rank: 400 }); - - app.commands.addCommand(CommandIDs.runCells, { - execute: args => { - if (!notebookTracker) { - return null; + app.commands.addCommand(CommandIDs.displayH1Numbering, { + label: trans.__('Show first-level heading number'), + execute: () => { + if (toc.model) { + toc.model.setConfiguration({ + numberingH1: !toc.model.configuration.numberingH1 + }); } + }, + isEnabled: () => + toc.model?.supportedOptions.includes('numberingH1') ?? false, + isToggled: () => toc.model?.configuration.numberingH1 ?? false + }); - const panel = notebookTracker.currentWidget; - if (panel == null) { - return; + app.commands.addCommand(CommandIDs.displayNumbering, { + label: trans.__('Show heading number in the document'), + icon: args => (args.toolbar ? numberingIcon : undefined), + execute: () => { + if (toc.model) { + toc.model.setConfiguration({ + numberHeaders: !toc.model.configuration.numberHeaders + }); + app.commands.notifyCommandChanged(CommandIDs.displayNumbering); } + }, + isEnabled: () => + toc.model?.supportedOptions.includes('numberHeaders') ?? false, + isToggled: () => toc.model?.configuration.numberHeaders ?? false + }); - const cells = panel.content.widgets; - if (cells === undefined) { - return; + app.commands.addCommand(CommandIDs.displayOutputNumbering, { + label: trans.__('Show output headings'), + execute: () => { + if (toc.model) { + toc.model.setConfiguration({ + includeOutput: !toc.model.configuration.includeOutput + }); } + }, + isEnabled: () => + toc.model?.supportedOptions.includes('includeOutput') ?? false, + isToggled: () => toc.model?.configuration.includeOutput ?? false + }); - const activeCell = (toc.activeEntry as INotebookHeading).cellRef; - - if (activeCell instanceof MarkdownCell) { - let level = activeCell.headingInfo.level; - for (let i = cells.indexOf(activeCell) + 1; i < cells.length; i++) { - const cell = cells[i]; - if ( - cell instanceof MarkdownCell && - cell.headingInfo.level <= level && - cell.headingInfo.level > -1 - ) { - break; - } - if (cell instanceof CodeCell) { - void CodeCell.execute(cell, panel.sessionContext); - } - } - } else { - if (activeCell instanceof CodeCell) { - void CodeCell.execute(activeCell, panel.sessionContext); + app.commands.addCommand(CommandIDs.showPanel, { + label: trans.__('Table of Contents'), + execute: () => { + app.shell.activateById(toc.id); + } + }); + + function someExpanded(model: TableOfContents.Model): boolean { + return model.headings.some(h => !(h.collapsed ?? false)); + } + + app.commands.addCommand(CommandIDs.toggleCollapse, { + label: () => + toc.model && !someExpanded(toc.model) + ? trans.__('Expand All Headings') + : trans.__('Collapse All Headings'), + icon: args => + args.toolbar + ? toc.model && !someExpanded(toc.model) + ? expandAllIcon + : collapseAllIcon + : undefined, + execute: () => { + if (toc.model) { + if (someExpanded(toc.model)) { + toc.model.toggleCollapse({ collapsed: true }); + } else { + toc.model.toggleCollapse({ collapsed: false }); } } }, - label: trans.__('Run Cell(s)') + isEnabled: () => toc.model !== null }); + const tracker = new TableOfContentsTracker(); + if (restorer) { // Add the ToC widget to the application restorer: restorer.add(toc, '@jupyterlab/toc:plugin'); @@ -138,7 +168,36 @@ async function activateTOC( let settings: ISettingRegistry.ISettings | undefined; if (settingRegistry) { try { - settings = await settingRegistry.load('@jupyterlab/toc-extension:plugin'); + settings = await settingRegistry.load(registry.id); + const updateSettings = (plugin: ISettingRegistry.ISettings) => { + const composite = plugin.composite; + for (const key of [...Object.keys(configuration)]) { + const value = composite[key] as any; + if (value !== undefined) { + configuration[key] = value; + } + } + + if (labShell) { + for (const widget of labShell.widgets('main')) { + const model = tracker.get(widget); + if (model) { + model.setConfiguration(configuration); + } + } + } else { + if (app.shell.currentWidget) { + const model = tracker.get(app.shell.currentWidget); + if (model) { + model.setConfiguration(configuration); + } + } + } + }; + if (settings) { + settings.changed.connect(updateSettings); + updateSettings(settings); + } } catch (error) { console.error( `Failed to load settings for the Table of Contents extension.\n\n${error}` @@ -146,56 +205,64 @@ async function activateTOC( } } - // Create a notebook generator: - if (notebookTracker) { - const notebookGenerator = createNotebookGenerator( - notebookTracker, - toc, - rendermime.sanitizer, - translator, - settings - ); - registry.add(notebookGenerator); - } + // Set up the panel toolbar + const numbering = new CommandToolbarButton({ + commands: app.commands, + id: CommandIDs.displayNumbering, + args: { + toolbar: true + }, + label: '' + }); + numbering.addClass('jp-toc-numberingButton'); + toc.toolbar.addItem('display-numbering', numbering); - // Create a Markdown generator: - if (editorTracker) { - const markdownGenerator = createMarkdownGenerator( - editorTracker, - toc, - rendermime.sanitizer, - translator, - settings - ); - registry.add(markdownGenerator); - - // Create a LaTeX generator: - const latexGenerator = createLatexGenerator(editorTracker); - registry.add(latexGenerator); - - // Create a Python generator: - const pythonGenerator = createPythonGenerator(editorTracker); - registry.add(pythonGenerator); - } + toc.toolbar.addItem('spacer', Toolbar.createSpacerItem()); - // Create a rendered Markdown generator: - if (markdownViewerTracker) { - const renderedMarkdownGenerator = createRenderedMarkdownGenerator( - markdownViewerTracker, - toc, - rendermime.sanitizer, - translator, - settings - ); - registry.add(renderedMarkdownGenerator); - } + toc.toolbar.addItem( + 'collapse-all', + new CommandToolbarButton({ + commands: app.commands, + id: CommandIDs.toggleCollapse, + args: { + toolbar: true + }, + label: '' + }) + ); + + const toolbarMenu = new MenuSvg({ commands: app.commands }); + toolbarMenu.addItem({ + command: CommandIDs.displayH1Numbering + }); + toolbarMenu.addItem({ + command: CommandIDs.displayOutputNumbering + }); + const menuButton = new ToolbarButton({ + tooltip: trans.__('More actionsâ€Ļ'), + icon: ellipsesIcon, + actualOnClick: true, + onClick: () => { + const bbox = menuButton.node.getBoundingClientRect(); + toolbarMenu.open(bbox.x, bbox.bottom); + } + }); + toc.toolbar.addItem('submenu', menuButton); + + // Add the ToC to the left area: + app.shell.add(toc, 'left', { rank: 400, type: 'Table of Contents' }); // Update the ToC when the active widget changes: if (labShell) { labShell.currentChanged.connect(onConnect); } - return registry; + // Connect to current widget + void app.restored.then(() => { + onConnect(); + }); + + return tracker; /** * Callback invoked when the active widget changes. @@ -207,41 +274,69 @@ async function activateTOC( if (!widget) { return; } - let generator = registry.find(widget); - if (!generator) { - // If the previously used widget is still available, stick with it. - // Otherwise, set the current ToC widget to null. - if (toc.current && toc.current.widget.isDisposed) { - toc.current = null; + let model = tracker.get(widget); + if (!model) { + model = tocRegistry.getModel(widget, configuration) ?? null; + if (model) { + tracker.add(widget, model); } - return; + + widget.disposed.connect(() => { + model?.dispose(); + }); } - toc.current = { widget, generator }; + + if (toc.model) { + toc.model.headingsChanged.disconnect(onCollapseChange); + toc.model.collapseChanged.disconnect(onCollapseChange); + } + + toc.model = model; + if (toc.model) { + toc.model.headingsChanged.connect(onCollapseChange); + toc.model.collapseChanged.connect(onCollapseChange); + } + setToolbarButtonsState(); + } + + function setToolbarButtonsState() { + app.commands.notifyCommandChanged(CommandIDs.displayNumbering); + app.commands.notifyCommandChanged(CommandIDs.toggleCollapse); + } + + function onCollapseChange() { + app.commands.notifyCommandChanged(CommandIDs.toggleCollapse); } } /** - * Initialization data for the ToC extension. - * - * @private + * Table of contents registry plugin. */ -const extension: JupyterFrontEndPlugin = { - id: '@jupyterlab/toc:plugin', +const registry: JupyterFrontEndPlugin = { + id: '@jupyterlab/toc-extension:registry', + description: 'Provides the table of contents registry.', autoStart: true, provides: ITableOfContentsRegistry, - requires: [IDocumentManager, IRenderMimeRegistry, ITranslator], - optional: [ - IEditorTracker, - ILayoutRestorer, - ILabShell, - IMarkdownViewerTracker, - INotebookTracker, - ISettingRegistry - ], + activate: (): ITableOfContentsRegistry => { + // Create the ToC registry + return new TableOfContentsRegistry(); + } +}; + +/** + * Table of contents tracker plugin. + */ +const tracker: JupyterFrontEndPlugin = { + id: '@jupyterlab/toc-extension:tracker', + description: 'Adds the table of content widget and provides its tracker.', + autoStart: true, + provides: ITableOfContentsTracker, + requires: [ITableOfContentsRegistry], + optional: [ITranslator, ILayoutRestorer, ILabShell, ISettingRegistry], activate: activateTOC }; /** * Exports. */ -export default extension; +export default [registry, tracker]; diff --git a/packages/toc-extension/style/base.css b/packages/toc-extension/style/base.css new file mode 100644 index 000000000000..1b66edd7fd16 --- /dev/null +++ b/packages/toc-extension/style/base.css @@ -0,0 +1,16 @@ +/*----------------------------------------------------------------------------- +| Copyright (c) Jupyter Development Team. +| Distributed under the terms of the Modified BSD License. +|----------------------------------------------------------------------------*/ + +.jp-toc-numberingButton:hover button.lm-mod-toggled.jp-Button.jp-mod-minimal { + background-color: var(--jp-inverse-layout-color4); +} + +.jp-toc-numberingButton button.lm-mod-toggled .jp-icon3[fill] { + fill: var(--jp-layout-color1); +} + +.jp-toc-numberingButton button.lm-mod-toggled.jp-Button.jp-mod-minimal { + background-color: var(--jp-inverse-layout-color3); +} diff --git a/packages/toc-extension/style/index.css b/packages/toc-extension/style/index.css index 2efcfd5d1c68..aa33799b71b6 100644 --- a/packages/toc-extension/style/index.css +++ b/packages/toc-extension/style/index.css @@ -5,11 +5,6 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ @import url('~@jupyterlab/ui-components/style/index.css'); -@import url('~@jupyterlab/rendermime/style/index.css'); @import url('~@jupyterlab/application/style/index.css'); -@import url('~@jupyterlab/docmanager/style/index.css'); -@import url('~@jupyterlab/cells/style/index.css'); -@import url('~@jupyterlab/fileeditor/style/index.css'); -@import url('~@jupyterlab/markdownviewer/style/index.css'); -@import url('~@jupyterlab/notebook/style/index.css'); @import url('~@jupyterlab/toc/style/index.css'); +@import url('./base.css'); diff --git a/packages/toc-extension/style/index.js b/packages/toc-extension/style/index.js index 704a9e6d391a..e52808bcf98c 100644 --- a/packages/toc-extension/style/index.js +++ b/packages/toc-extension/style/index.js @@ -5,11 +5,7 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ import '@jupyterlab/ui-components/style/index.js'; -import '@jupyterlab/rendermime/style/index.js'; import '@jupyterlab/application/style/index.js'; -import '@jupyterlab/docmanager/style/index.js'; -import '@jupyterlab/cells/style/index.js'; -import '@jupyterlab/fileeditor/style/index.js'; -import '@jupyterlab/markdownviewer/style/index.js'; -import '@jupyterlab/notebook/style/index.js'; import '@jupyterlab/toc/style/index.js'; + +import './base.css'; diff --git a/packages/toc-extension/tsconfig.json b/packages/toc-extension/tsconfig.json index d9f730114cfb..1d0f399e63d3 100644 --- a/packages/toc-extension/tsconfig.json +++ b/packages/toc-extension/tsconfig.json @@ -9,24 +9,6 @@ { "path": "../application" }, - { - "path": "../cells" - }, - { - "path": "../docmanager" - }, - { - "path": "../fileeditor" - }, - { - "path": "../markdownviewer" - }, - { - "path": "../notebook" - }, - { - "path": "../rendermime" - }, { "path": "../settingregistry" }, diff --git a/packages/toc/.vscode/launch.json b/packages/toc/.vscode/launch.json new file mode 100644 index 000000000000..66fb4b825a88 --- /dev/null +++ b/packages/toc/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "attach", + "name": "Attach to jest", + // Usage: + // Open the parent directory in VSCode + // Run `jlpm test:debug:watch` in a terminal + // Run this debugging task + "port": 9229 + } + ] +} diff --git a/packages/toc/babel.config.js b/packages/toc/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/packages/toc/babel.config.js +++ b/packages/toc/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/packages/toc/jest.config.js b/packages/toc/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/toc/jest.config.js +++ b/packages/toc/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/toc/package.json b/packages/toc/package.json index 2d5d568e3c40..b58f46fdfa00 100644 --- a/packages/toc/package.json +++ b/packages/toc/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/toc", - "version": "5.6.6", + "version": "6.0.8", "description": "JupyterLab - Table of Contents widget", "keywords": [ "jupyterlab" @@ -26,7 +26,8 @@ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "schema/*.json", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -35,43 +36,33 @@ "docs": "typedoc src", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/cells": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/docmanager": "^3.6.6", - "@jupyterlab/docregistry": "^3.6.6", - "@jupyterlab/fileeditor": "^3.6.6", - "@jupyterlab/markdownviewer": "^3.6.6", - "@jupyterlab/notebook": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/translation": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@lumino/coreutils": "^1.11.0", - "@lumino/domutils": "^1.8.0", - "@lumino/messaging": "^1.10.0", - "@lumino/signaling": "^1.10.0", - "@lumino/widgets": "^1.37.2", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/docregistry": "^4.0.8", + "@jupyterlab/observables": "^5.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/messaging": "^2.0.1", + "@lumino/signaling": "^2.1.2", + "@lumino/widgets": "^2.3.0", + "react": "^18.2.0" }, "devDependencies": { - "@babel/core": "^7.10.2", - "@babel/preset-env": "^7.10.2", - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "@types/react": "^17.0.0", - "@types/react-dom": "^17.0.0", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "@types/react": "^18.0.26", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "ts-jest": "^26.3.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/toc/src/factory.ts b/packages/toc/src/factory.ts new file mode 100644 index 000000000000..1dfca07946a0 --- /dev/null +++ b/packages/toc/src/factory.ts @@ -0,0 +1,108 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { IWidgetTracker } from '@jupyterlab/apputils'; +import { ActivityMonitor, PathExt } from '@jupyterlab/coreutils'; +import { IDocumentWidget } from '@jupyterlab/docregistry'; +import { Widget } from '@lumino/widgets'; +import { TableOfContentsModel } from './model'; +import { TableOfContents } from './tokens'; + +/** + * Timeout for throttling ToC rendering following model changes. + * + * @private + */ +const RENDER_TIMEOUT = 1000; + +/** + * Abstract table of contents model factory for IDocumentWidget. + */ +export abstract class TableOfContentsFactory< + W extends IDocumentWidget, + H extends TableOfContents.IHeading = TableOfContents.IHeading +> implements TableOfContents.IFactory +{ + /** + * Constructor + * + * @param tracker Widget tracker + */ + constructor(protected tracker: IWidgetTracker) {} + + /** + * Whether the factory can handle the widget or not. + * + * @param widget - widget + * @returns boolean indicating a ToC can be generated + */ + isApplicable(widget: Widget): boolean { + if (!this.tracker.has(widget)) { + return false; + } + + return true; + } + + /** + * Create a new table of contents model for the widget + * + * @param widget - widget + * @param configuration - Table of contents configuration + * @returns The table of contents model + */ + createNew( + widget: W, + configuration?: TableOfContents.IConfig + ): TableOfContentsModel { + const model = this._createNew(widget, configuration); + + const context = widget.context; + + const updateHeadings = () => { + model.refresh().catch(reason => { + console.error('Failed to update the table of contents.', reason); + }); + }; + const monitor = new ActivityMonitor({ + signal: context.model.contentChanged, + timeout: RENDER_TIMEOUT + }); + monitor.activityStopped.connect(updateHeadings); + + const updateTitle = () => { + model.title = PathExt.basename(context.localPath); + }; + context.pathChanged.connect(updateTitle); + + context.ready + .then(() => { + updateTitle(); + updateHeadings(); + }) + .catch(reason => { + console.error(`Failed to initiate headings for ${context.localPath}.`); + }); + + widget.disposed.connect(() => { + monitor.activityStopped.disconnect(updateHeadings); + context.pathChanged.disconnect(updateTitle); + }); + + return model; + } + + /** + * Abstract table of contents model instantiation to allow + * override by real implementation to customize it. The public + * `createNew` contains the signal connections standards for IDocumentWidget + * when the model has been instantiated. + * + * @param widget + * @param configuration + */ + protected abstract _createNew( + widget: W, + configuration?: TableOfContents.IConfig + ): TableOfContentsModel; +} diff --git a/packages/toc/src/generators/latex/index.ts b/packages/toc/src/generators/latex/index.ts deleted file mode 100644 index 44a31ebd181b..000000000000 --- a/packages/toc/src/generators/latex/index.ts +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { IDocumentWidget } from '@jupyterlab/docregistry'; -import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor'; -import { TableOfContentsRegistry as Registry } from '../../registry'; -import { IHeading } from '../../utils/headings'; - -/** - * Maps LaTeX section headings to HTML header levels. - * - * ## Notes - * - * - As `part` and `chapter` section headings appear to be less common, assign them to heading level 1. - * - * @private - */ -const LATEX_LEVELS: { [label: string]: number } = { - part: 1, // Only available for report and book classes - chapter: 1, // Only available for report and book classes - section: 1, - subsection: 2, - subsubsection: 3, - paragraph: 4, - subparagraph: 5 -}; - -/** - * Converts array elements to "entries". - * - * @private - * @param arr - input array - * @returns input array - * - * @example - * const arr = toEntries([4,5,6]); - * // returns [[4,0], [5,1], [6,2]] - */ -function toEntries(arr: Array): Array<[any, number]> { - for (let i = 0; i < arr.length; i++) { - arr[i] = [arr[i], i]; - } - return arr; -} - -/** - * Returns a boolean indicating whether this ToC generator is enabled. - * - * @private - * @param editor - editor widget - * @returns boolean indicating whether this ToC generator is enabled - */ -function isEnabled(editor: IDocumentWidget) { - // Only enable this if the editor MIME type matches one of a few LaTeX variants: - let mime = editor.content.model.mimeType; - return mime === 'text/x-latex' || mime === 'text/x-stex'; -} - -/** - * Generates a table of contents. - * - * @private - * @param editor - editor widget - * @returns a list of headings - */ -function generate(editor: IDocumentWidget): IHeading[] { - // Split the text into lines: - let lines = editor.content.model.value.text.split('\n') as Array; - - // Convert the list into "entries" so we can use the line number to scroll the editor upon ToC item click: - lines = toEntries(lines); - - // Iterate over the lines to get the heading level and text for each line: - let headings: IHeading[] = []; - for (let i = 0; i < lines.length; i++) { - const RE = /^\s*\\(section|subsection|subsubsection){(.+)}/; - const match = lines[i][0].match(RE); - if (match) { - headings.push({ - text: match[2], - level: LATEX_LEVELS[match[1]], - onClick: onClick(lines[i][1]) - }); - } - } - return headings; - - /** - * Returns a "click" handler. - * - * @private - * @param line - line number - * @returns click handler - */ - function onClick(line: number) { - return () => { - editor.content.editor.setCursorPosition({ - line: line, - column: 0 - }); - }; - } -} - -/** - * Returns a ToC generator for LaTeX files. - * - * @private - * @param tracker - file editor tracker - * @returns ToC generator capable of parsing LaTeX files - */ -function createLatexGenerator( - tracker: IEditorTracker -): Registry.IGenerator> { - return { - tracker, - usesLatex: true, - isEnabled: isEnabled, - generate: generate - }; -} - -/** - * Exports. - */ -export { createLatexGenerator }; diff --git a/packages/toc/src/generators/markdown/get_headings.ts b/packages/toc/src/generators/markdown/get_headings.ts deleted file mode 100644 index f4c671b83e69..000000000000 --- a/packages/toc/src/generators/markdown/get_headings.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { generateNumbering } from '../../utils/generate_numbering'; -import { INumberedHeading } from '../../utils/headings'; -import { INumberingDictionary } from '../../utils/numbering_dictionary'; -import { parseHeading } from '../../utils/parse_heading'; - -/** - * Returns a "click" handler. - * - * @private - * @param line - line number - * @returns "click" handler - */ -type onClickFactory = (line: number) => () => void; - -/** - * Parses a provided string and returns a list of headings. - * - * @private - * @param text - input text - * @param onClick - callback which returns a "click" handler - * @param dict - numbering dictionary - * @param numberingH1 - whether first level header should be numbered - * @returns list of headings - */ -function getHeadings( - text: string, - onClick: onClickFactory, - dict: INumberingDictionary, - numberingH1: boolean -): INumberedHeading[] { - // Split the text into lines: - const lines = text.split('\n'); - - // Iterate over the lines to get the header level and text for each line: - let headings: INumberedHeading[] = []; - let FLG; - for (let i = 0; i < lines.length; i++) { - let line = lines[i]; - - // Don't check for Markdown headings if in a code block: - if (line.indexOf('```') === 0) { - FLG = !FLG; - } - if (FLG) { - continue; - } - line += lines[i + 1] ? '\n' + lines[i + 1] : ''; - const heading = parseHeading(line); // append the next line to capture alternative style Markdown headings - if (heading) { - let level = heading.level; - if (!numberingH1) { - level -= 1; - } - headings.push({ - text: heading.text, - numbering: generateNumbering(dict, level), - level: heading.level, - onClick: onClick(i) - }); - } - } - return headings; -} - -/** - * Exports. - */ -export { getHeadings }; diff --git a/packages/toc/src/generators/markdown/get_rendered_headings.ts b/packages/toc/src/generators/markdown/get_rendered_headings.ts deleted file mode 100644 index af82fbc0b87d..000000000000 --- a/packages/toc/src/generators/markdown/get_rendered_headings.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { ISanitizer } from '@jupyterlab/apputils'; -import { generateNumbering } from '../../utils/generate_numbering'; -import { INumberedHeading } from '../../utils/headings'; -import { INumberingDictionary } from '../../utils/numbering_dictionary'; -import { sanitizerOptions } from '../../utils/sanitizer_options'; - -/** - * Returns a "click" handler. - * - * @private - * @param heading - heading element - * @returns "click" handler - */ -function onClick(heading: Element) { - return () => { - heading.scrollIntoView(); - }; -} - -/** - * Processes an HTML element containing rendered Markdown and returns a list of headings. - * - * @private - * @param node - HTML element - * @param sanitizer - HTML sanitizer - * @param dict - numbering dictionary - * @param numbering - boolean indicating whether to enable numbering - * @param numberingH1 - whether first level header should be numbered - * @returns list of headings - */ -function getRenderedHeadings( - node: HTMLElement, - sanitizer: ISanitizer, - dict: INumberingDictionary, - numbering = true, - numberingH1 = true -): INumberedHeading[] { - let nodes = node.querySelectorAll('h1, h2, h3, h4, h5, h6'); - let headings: INumberedHeading[] = []; - for (let i = 0; i < nodes.length; i++) { - const heading = nodes[i]; - let level = parseInt(heading.tagName[1], 10); - let text = heading.textContent ? heading.textContent : ''; - let hide = !numbering; - - // Show/hide numbering DOM element based on user settings: - if (heading.getElementsByClassName('numbering-entry').length > 0) { - heading.removeChild(heading.getElementsByClassName('numbering-entry')[0]); - } - let html = sanitizer.sanitize(heading.innerHTML, sanitizerOptions); - html = html.replace('Âļ', ''); // remove the anchor symbol - - // Generate a numbering string: - if (!numberingH1) { - level -= 1; - } - let nstr = generateNumbering(dict, level); - // Generate the numbering DOM element: - let nhtml = ''; - if (!hide) { - nhtml = '' + nstr + ''; - } - // Append the numbering element to the document: - heading.innerHTML = nhtml + html; - - headings.push({ - level, - text: text.replace('Âļ', ''), - numbering: nstr, - html, - onClick: onClick(heading) - }); - } - return headings; -} - -/** - * Exports. - */ -export { getRenderedHeadings }; diff --git a/packages/toc/src/generators/markdown/index.ts b/packages/toc/src/generators/markdown/index.ts deleted file mode 100644 index cc703270165e..000000000000 --- a/packages/toc/src/generators/markdown/index.ts +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { ISanitizer } from '@jupyterlab/apputils'; -import { IDocumentWidget } from '@jupyterlab/docregistry'; -import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor'; -import { - IMarkdownViewerTracker, - MarkdownDocument -} from '@jupyterlab/markdownviewer'; -import { ITranslator, nullTranslator } from '@jupyterlab/translation'; -import { TableOfContentsRegistry as Registry } from '../../registry'; -import { TableOfContents } from '../../toc'; -import { INumberedHeading } from '../../utils/headings'; -import { isMarkdown } from '../../utils/is_markdown'; -import { OptionsManager } from './options_manager'; -import { render } from './render'; -import { toolbar } from './toolbar_generator'; -import { getHeadings } from './get_headings'; -import { getRenderedHeadings } from './get_rendered_headings'; -import { ISettingRegistry } from '@jupyterlab/settingregistry'; - -/** - * Returns a boolean indicating whether this ToC generator is enabled. - * - * @private - * @param editor - editor widget - * @returns boolean indicating whether this ToC generator is enabled - */ -function isEnabled(editor: IDocumentWidget) { - // Only enable this if the editor MIME type matches one of a few Markdown variants: - return isMarkdown(editor.content.model.mimeType); -} - -/** - * Generates a table of contents. - * - * @private - * @param editor - editor widget - * @param options - manage Markdown ToC generator options - * @returns a list of headings - */ -function generate( - editor: IDocumentWidget, - options?: OptionsManager -): INumberedHeading[] { - let dict = {}; - let numberingH1 = true; - if (options !== undefined) { - numberingH1 = options.numberingH1; - } - return getHeadings( - editor.content.model.value.text, - onClick, - dict, - numberingH1 - ); - - /** - * Returns a "click" handler. - * - * @private - * @param line - line number - * @returns click handler - */ - function onClick(line: number) { - return () => { - editor.content.editor.setCursorPosition({ - line: line, - column: 0 - }); - }; - } -} - -/** - * Returns a ToC generator for Markdown files. - * - * @private - * @param tracker - file editor tracker - * @param widget - table of contents widget - * @param sanitizer - HTML sanitizer - * @param settings - advanced settings for toc extension - * @returns ToC generator capable of parsing Markdown files - */ -function createMarkdownGenerator( - tracker: IEditorTracker, - widget: TableOfContents, - sanitizer: ISanitizer, - translator?: ITranslator, - settings?: ISettingRegistry.ISettings -): Registry.IGenerator> { - let numberingH1 = true; - if (settings) { - numberingH1 = settings.composite.numberingH1 as boolean; - } - const options = new OptionsManager(widget, { - numbering: true, - numberingH1: numberingH1, - sanitizer, - translator: translator || nullTranslator - }); - if (settings) { - settings.changed.connect(() => { - options.numberingH1 = settings.composite.numberingH1 as boolean; - }); - } - return { - tracker, - usesLatex: true, - options: options, - toolbarGenerator: generateToolbar, - itemRenderer: renderItem, - isEnabled: isEnabled, - generate: generate - }; - - /** - * Returns a toolbar generator. - * - * @private - * @returns toolbar generator - */ - function generateToolbar() { - return toolbar(options); - } - - /** - * Renders a table of contents item. - * - * @private - * @param item - heading to render - * @returns rendered item - */ - function renderItem(item: INumberedHeading) { - return render(options, item); - } -} - -/** - * Returns a ToC generator for rendered Markdown files. - * - * @param tracker - Markdown viewer tracker - * @param sanitizer - HTML sanitizer - * @param widget - table of contents widget - * @param settings - advanced settings for toc extension - * @returns ToC generator capable of parsing rendered Markdown files - */ -function createRenderedMarkdownGenerator( - tracker: IMarkdownViewerTracker, - widget: TableOfContents, - sanitizer: ISanitizer, - translator?: ITranslator, - settings?: ISettingRegistry.ISettings -): Registry.IGenerator { - let numberingH1 = true; - if (settings) { - numberingH1 = settings.composite.numberingH1 as boolean; - } - const options = new OptionsManager(widget, { - numbering: true, - numberingH1: numberingH1, - sanitizer, - translator: translator || nullTranslator - }); - if (settings) { - settings.changed.connect(() => { - options.numberingH1 = settings.composite.numberingH1 as boolean; - }); - } - return { - tracker, - usesLatex: true, - options: options, - toolbarGenerator: generateToolbar, - itemRenderer: renderItem, - generate: generate - }; - - /** - * Returns a toolbar generator. - * - * @private - * @returns toolbar generator - */ - function generateToolbar() { - return toolbar(options); - } - - /** - * Renders a table of contents item. - * - * @private - * @param item - heading to render - * @returns rendered item - */ - function renderItem(item: INumberedHeading) { - return render(options, item); - } - - /** - * Generates a table of contents. - * - * @private - * @param widget - Markdown document widget - * @returns a list of headings - */ - function generate(widget: MarkdownDocument): INumberedHeading[] { - let dict = {}; - return getRenderedHeadings( - widget.content.node, - sanitizer, - dict, - options.numbering, - options.numberingH1 - ); - } -} - -/** - * Exports. - */ -export { createMarkdownGenerator }; -export { createRenderedMarkdownGenerator }; diff --git a/packages/toc/src/generators/markdown/options_manager.ts b/packages/toc/src/generators/markdown/options_manager.ts deleted file mode 100644 index e5770a439257..000000000000 --- a/packages/toc/src/generators/markdown/options_manager.ts +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { ISanitizer } from '@jupyterlab/apputils'; -import { ITranslator, nullTranslator } from '@jupyterlab/translation'; -import { TableOfContentsRegistry as Registry } from '../../registry'; -import { TableOfContents } from '../../toc'; - -/** - * Interface describing constructor options. - * - * @private - */ -interface IOptions { - /** - * Boolean indicating whether items should be numbered. - */ - numbering: boolean; - - /** - * Boolean indicating whether h1 headers should be numbered. - */ - numberingH1: boolean; - - /** - * HTML sanitizer. - */ - sanitizer: ISanitizer; - - /** - * The application language translator. - */ - translator?: ITranslator; -} - -/** - * Class for managing Markdown ToC generator options. - * - * @private - */ -class OptionsManager implements Registry.IOptionsManager { - /** - * Returns an options manager. - * - * @param widget - table of contents widget - * @param options - generator options - * @returns options manager - */ - constructor(widget: TableOfContents, options: IOptions) { - this._numbering = options.numbering; - this._numberingH1 = options.numberingH1; - this._widget = widget; - this.translator = options.translator || nullTranslator; - this.sanitizer = options.sanitizer; - } - - /** - * HTML sanitizer. - */ - readonly sanitizer: ISanitizer; - - /** - * Gets/sets ToC generator numbering. - */ - set numbering(value: boolean) { - this._numbering = value; - this._widget.update(); - } - - get numbering() { - return this._numbering; - } - - /** - * Gets/sets ToC generator numbering h1 headers. - */ - set numberingH1(value: boolean) { - if (this._numberingH1 != value) { - this._numberingH1 = value; - this._widget.update(); - } - } - - get numberingH1() { - return this._numberingH1; - } - - /** - * Initializes options. - * - * ## Notes - * - * - This will **not** change notebook meta-data. - * - * @param numbering - boolean indicating whether to number items - */ - initializeOptions(numbering: boolean, numberingH1: boolean) { - this._numbering = numbering; - this._numberingH1 = numberingH1; - this._widget.update(); - } - - translator: ITranslator; - private _numbering: boolean; - private _numberingH1: boolean; - private _widget: TableOfContents; -} - -/** - * Exports. - */ -export { OptionsManager }; diff --git a/packages/toc/src/generators/markdown/render.tsx b/packages/toc/src/generators/markdown/render.tsx deleted file mode 100644 index 8d42bab248f8..000000000000 --- a/packages/toc/src/generators/markdown/render.tsx +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import * as React from 'react'; -import { INumberedHeading } from '../../utils/headings'; -import { sanitizerOptions } from '../../utils/sanitizer_options'; -import { OptionsManager } from './options_manager'; - -/** - * Renders a Markdown table of contents item. - * - * @private - * @param options - generator options - * @param item - numbered heading - * @returns rendered item - */ -function render(options: OptionsManager, item: INumberedHeading) { - let fontSizeClass = 'toc-level-size-' + item.level; - - // Render item numbering: - let numbering = item.numbering && options.numbering ? item.numbering : ''; - - // Render the item: - let jsx; - if (item.html) { - let html = options.sanitizer.sanitize(item.html, sanitizerOptions); - jsx = ( - - ); - } else { - jsx = {numbering + item.text}; - } - return jsx; -} - -/** - * Exports. - */ -export { render }; diff --git a/packages/toc/src/generators/markdown/toolbar_generator.tsx b/packages/toc/src/generators/markdown/toolbar_generator.tsx deleted file mode 100644 index b5a7b82a9e15..000000000000 --- a/packages/toc/src/generators/markdown/toolbar_generator.tsx +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { TranslationBundle } from '@jupyterlab/translation'; -import { numberingIcon } from '@jupyterlab/ui-components'; -import * as React from 'react'; -import { OptionsManager } from './options_manager'; - -/** - * Interface describing toolbar properties. - * - * @private - */ -interface IProperties {} - -/** - * Interface describing toolbar state. - * - * @private - */ -interface IState { - /** - * Boolean indicating whether numbering is enabled. - */ - numbering: boolean; -} - -/** - * Returns a component for rendering a Markdown table of contents toolbar. - * - * @private - * @param options - generator options - * @returns toolbar component - */ -function toolbar(options: OptionsManager) { - return class Toolbar extends React.Component { - /** - * Returns a component for rendering a Markdown table of contents toolbar. - * - * @param props - toolbar properties - * @returns toolbar component - */ - constructor(props: IProperties) { - super(props); - this.state = { numbering: false }; - options.initializeOptions(false, options.numberingH1); - this._trans = options.translator.load('jupyterlab'); - } - - /** - * Renders a toolbar. - * - * @returns rendered toolbar - */ - render() { - const toggleNumbering = () => { - options.numbering = !options.numbering; - this.setState({ numbering: options.numbering }); - }; - const icon = ( -
    toggleNumbering()} - role="text" - aria-label={this._trans.__('Toggle Auto-Numbering')} - title={this._trans.__('Toggle Auto-Numbering')} - className={ - this.state.numbering - ? 'toc-toolbar-icon-selected' - : 'toc-toolbar-icon' - } - > - -
    - ); - return ( -
    -
    {icon}
    -
    - ); - } - - _trans: TranslationBundle; - }; -} - -/** - * Exports. - */ -export { toolbar }; diff --git a/packages/toc/src/generators/notebook/append_collapsible_heading.ts b/packages/toc/src/generators/notebook/append_collapsible_heading.ts deleted file mode 100644 index b55c1816069d..000000000000 --- a/packages/toc/src/generators/notebook/append_collapsible_heading.ts +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { INotebookHeading } from '../../utils/headings'; -import { isHeadingFiltered } from './is_heading_filtered'; - -/** - * Appends a collapsible notebook heading to a list of headings. - * - * @private - * @param headings - list of notebook headings - * @param heading - rendered heading - * @param prev - previous heading - * @param collapseLevel - collapse level - * @param tags - filter tags - * @param collapsed - boolean indicating whether a heading is collapsed - * @param cellCollapseMetadata - indicates which metadata string to use based on the cellSyncSetting - * @returns result tuple - */ -function appendCollapsibleHeading( - headings: INotebookHeading[], - heading: INotebookHeading, - prev: INotebookHeading | null, - collapseLevel: number, - tags: string[], - collapsed: boolean, - cellCollapseMetadata: string -): [INotebookHeading[], INotebookHeading | null, number] { - const len = headings.length; - if (!isHeadingFiltered(heading, tags)) { - // If the previous heading is a higher level heading, update the heading to note that it has a child heading... - if (prev && prev.type === 'header' && prev.level < heading.level) { - for (let j = len - 1; j >= 0; j--) { - if (headings[j] === prev) { - // TODO: can a heading be the child of multiple headings? If not, we can `break` here upon finding a parent heading, so we don't traverse the entire heading list... - headings[j].hasChild = true; - } - } - } - // If the collapse level doesn't include the heading, or, if there is no collapsing, add to headings and adjust the collapse level... - if (collapseLevel >= heading.level || collapseLevel < 0) { - headings.push(heading); - collapseLevel = collapsed ? heading.level : -1; - } - prev = heading; - } else if (prev && heading.level <= prev.level) { - // If the heading is filtered out and has a lower level previous heading, determine if the heading has a parent... - let parent = false; - let k = len - 1; - for (; k >= 0; k--) { - if (headings[k].level < heading.level) { - prev = headings[k]; - parent = true; - break; - } - } - // If there is no parent, reset collapsing... - if (parent) { - const isCollapsed = headings[k + 1].cellRef.model.metadata.get( - cellCollapseMetadata - ) as boolean; - collapseLevel = isCollapsed ? headings[k + 1].level : -1; - } else { - prev = null; - collapseLevel = -1; - } - } - return [headings, prev, collapseLevel]; -} - -/** - * Exports. - */ -export { appendCollapsibleHeading }; diff --git a/packages/toc/src/generators/notebook/append_heading.ts b/packages/toc/src/generators/notebook/append_heading.ts deleted file mode 100644 index 890de947b392..000000000000 --- a/packages/toc/src/generators/notebook/append_heading.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { INotebookHeading } from '../../utils/headings'; -import { isHeadingFiltered } from './is_heading_filtered'; - -/** - * Appends a notebook heading to a list of headings. - * - * @private - * @param headings - list of notebook headings - * @param heading - rendered heading - * @param prev - previous heading - * @param collapseLevel - collapse level - * @param tags - filter tags - * @returns result tuple - */ -export function appendHeading( - headings: INotebookHeading[], - heading: INotebookHeading, - prev: INotebookHeading | null, - collapseLevel: number, - tags: string[] -): [INotebookHeading[], INotebookHeading | null] { - if (heading && !isHeadingFiltered(heading, tags) && heading.text) { - // Determine whether this heading is a child of a "header" notebook heading... - if (prev && prev.type === 'header') { - for (let j = headings.length - 1; j >= 0; j--) { - if (headings[j] === prev) { - // TODO: can a heading be the child of multiple headings? If not, we can `break` here upon finding a parent heading, so we don't traverse the entire heading list... - headings[j].hasChild = true; - } - } - } - if (collapseLevel < 0) { - headings.push(heading); - } - prev = heading; - } - return [headings, prev]; -} diff --git a/packages/toc/src/generators/notebook/append_markdown_heading.ts b/packages/toc/src/generators/notebook/append_markdown_heading.ts deleted file mode 100644 index 032064519fa6..000000000000 --- a/packages/toc/src/generators/notebook/append_markdown_heading.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { INotebookHeading } from '../../utils/headings'; -import { appendCollapsibleHeading } from './append_collapsible_heading'; -import { appendHeading } from './append_heading'; - -/** - * Appends a Markdown notebook heading to a list of headings. - * - * @private - * @param headings - list of notebook headings - * @param heading - rendered heading - * @param prev - previous heading - * @param collapseLevel - collapse level - * @param tags - filter tags - * @param collapsed - boolean indicating whether a heading is collapsed - * @param showMarkdown - boolean indicating whether to show Markdown previews - * @param cellCollapseMetadata - indicates which metadata string to use based on the cellSyncSetting - * @returns result tuple - */ -function appendMarkdownHeading( - heading: INotebookHeading | undefined, - headings: INotebookHeading[], - prev: INotebookHeading | null, - collapseLevel: number, - tags: string[], - collapsed: boolean, - showMarkdown: boolean, - cellCollapseMetadata: string -): [INotebookHeading[], INotebookHeading | null, number] { - if (heading && heading.type === 'markdown' && showMarkdown) { - // Append a Markdown preview heading: - [headings, prev] = appendHeading( - headings, - heading, - prev, - collapseLevel, - tags - ); - } else if (heading && heading.type === 'header') { - [headings, prev, collapseLevel] = appendCollapsibleHeading( - headings, - heading, - prev, - collapseLevel, - tags, - collapsed, - cellCollapseMetadata - ); - } - return [headings, prev, collapseLevel]; -} - -/** - * Exports. - */ -export { appendMarkdownHeading }; diff --git a/packages/toc/src/generators/notebook/codemirror.tsx b/packages/toc/src/generators/notebook/codemirror.tsx deleted file mode 100644 index 40f8253a52c5..000000000000 --- a/packages/toc/src/generators/notebook/codemirror.tsx +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { ISanitizer } from '@jupyterlab/apputils'; -import * as React from 'react'; -import { INotebookHeading } from '../../utils/headings'; -import { sanitizerOptions } from '../../utils/sanitizer_options'; - -/** - * Interface describing code component properties. - * - * @private - */ -interface IProperties { - /** - * HTML sanitizer. - */ - sanitizer: ISanitizer; - - /** - * Notebook heading. - */ - heading: INotebookHeading; -} - -/** - * Interface describing code component state. - */ -interface IState { - /** - * Notebook heading. - */ - heading: INotebookHeading; -} - -/** - * Class for rendering a code component. - * - * @private - */ -class CodeComponent extends React.Component { - /** - * Returns a code component. - * - * @param props - component properties - * @returns code component - */ - constructor(props: IProperties) { - super(props); - this.state = { heading: props.heading }; - } - - /** - * Updates code component state. - * - * @param props - component properties - */ - UNSAFE_componentWillReceiveProps(nextProps: IProperties) { - this.setState({ heading: nextProps.heading }); - } - - /** - * Renders a code component. - * - * @returns rendered component - */ - render() { - // Get the current rendered CodeMirror: - let html = this.state.heading.cellRef!.editor.host.innerHTML; - - // Sanitize the HTML: - html = this.props.sanitizer.sanitize(html, sanitizerOptions); - - return ( -
    - ); - } -} - -/** - * Exports. - */ -export { CodeComponent }; diff --git a/packages/toc/src/generators/notebook/get_code_cell_heading.ts b/packages/toc/src/generators/notebook/get_code_cell_heading.ts deleted file mode 100644 index d2be518e2085..000000000000 --- a/packages/toc/src/generators/notebook/get_code_cell_heading.ts +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { Cell } from '@jupyterlab/cells'; -import { INotebookHeading, RunningStatus } from '../../utils/headings'; - -/** - * Returns a "click" handler. - * - * @private - * @param line - line number - * @returns "click" handler - */ -type onClickFactory = (line: number) => () => void; - -/** - * Returns a code entry notebook heading from a code string. - * - * @private - * @param text - code string - * @param onClick - callback which returns a "click" handler - * @param executionCount - execution count - * @param lastLevel - last heading level - * @param cellRef - cell reference - * @param index - index of referenced cell relative to other cells in the notebook - * @returns notebook heading - */ -function getCodeCellHeading( - text: string, - onClick: onClickFactory, - executionCount: string, - lastLevel: number, - cellRef: Cell, - index: number = -1, - isRunning = RunningStatus.Idle -): INotebookHeading { - let headings: INotebookHeading[] = []; - if (index === -1) { - console.warn( - 'Deprecation warning! index argument will become mandatory in the next version' - ); - } - if (text) { - const lines = text.split('\n'); - const len = Math.min(lines.length, 3); - let str = ''; - let i = 0; - for (; i < len - 1; i++) { - str += lines[i] + '\n'; - } - str += lines[i]; - headings.push({ - text: str, - level: lastLevel + 1, - onClick: onClick(0), - type: 'code', - prompt: executionCount, - cellRef: cellRef, - hasChild: false, - index: index, - isRunning - }); - } - return headings[0]; -} - -/** - * Exports. - */ -export { getCodeCellHeading }; diff --git a/packages/toc/src/generators/notebook/get_last_heading_level.ts b/packages/toc/src/generators/notebook/get_last_heading_level.ts deleted file mode 100644 index ce046f58be6a..000000000000 --- a/packages/toc/src/generators/notebook/get_last_heading_level.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { INotebookHeading } from '../../utils/headings'; - -/** - * Returns the last heading level. - * - * @private - * @param headings - list of notebook headings - * @returns heading level - */ -function getLastHeadingLevel(headings: INotebookHeading[]): number { - if (headings.length > 0) { - let loc = headings.length - 1; - while (loc >= 0) { - if (headings[loc].type === 'header') { - return headings[loc].level; - } - loc -= 1; - } - } - return 0; -} - -/** - * Exports. - */ -export { getLastHeadingLevel }; diff --git a/packages/toc/src/generators/notebook/get_markdown_heading.ts b/packages/toc/src/generators/notebook/get_markdown_heading.ts deleted file mode 100644 index 90537d55d934..000000000000 --- a/packages/toc/src/generators/notebook/get_markdown_heading.ts +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { Cell } from '@jupyterlab/cells'; -import { generateNumbering } from '../../utils/generate_numbering'; -import { INotebookHeading, RunningStatus } from '../../utils/headings'; -import { parseHeading } from '../../utils/parse_heading'; - -/** - * Returns a "click" handler. - * - * @private - * @param line - line number - * @returns "click" handler - */ -type onClickFactory = (line: number) => () => void; - -/** - * Parses a Markdown string and returns a notebook heading. - * - * @private - * @param text - Markdown string - * @param onClick - callback which returns a "click" handler - * @param dict - numbering dictionary - * @param lastLevel - last level - * @param cellRef - cell reference - * @param index - index of referenced cell relative to other cells in the notebook - * @returns notebook heading - */ -function getMarkdownHeadings( - text: string, - onClick: onClickFactory, - dict: any, - lastLevel: number, - cellRef: Cell, - index: number = -1, - isRunning = RunningStatus.Idle -): INotebookHeading[] { - const callback = onClick(0); - let headings: INotebookHeading[] = []; - if (index === -1) { - console.warn( - 'Deprecation warning! index argument will become mandatory in the next version' - ); - } - for (const line of text.split('\n')) { - if (line) { - const heading = parseHeading(line); - if (heading) { - headings.push({ - text: heading.text, - level: heading.level, - numbering: generateNumbering(dict, heading.level), - onClick: callback, - type: 'header', - cellRef: cellRef, - hasChild: false, - isRunning, - index - }); - } else { - headings.push({ - text: line, - level: lastLevel + 1, - onClick: callback, - type: 'markdown', - cellRef: cellRef, - hasChild: false, - isRunning, - index - }); - } - } - } - return headings; -} - -/** - * Exports. - */ -export { getMarkdownHeadings }; diff --git a/packages/toc/src/generators/notebook/get_rendered_html_heading.ts b/packages/toc/src/generators/notebook/get_rendered_html_heading.ts deleted file mode 100644 index 150a726aee5e..000000000000 --- a/packages/toc/src/generators/notebook/get_rendered_html_heading.ts +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { ISanitizer } from '@jupyterlab/apputils'; -import { Cell } from '@jupyterlab/cells'; -import { generateNumbering } from '../../utils/generate_numbering'; -import { INotebookHeading, RunningStatus } from '../../utils/headings'; -import { INumberingDictionary } from '../../utils/numbering_dictionary'; -import { sanitizerOptions } from '../../utils/sanitizer_options'; - -/** - * Returns a "click" handler. - * - * @private - * @param el - HTML element - * @returns "click" handler - */ -type onClickFactory = (el: Element) => () => void; - -/** - * Returns a notebook heading from an HTML element. - * - * @private - * @param node - HTML element - * @param onClick - callback which returns a "click" handler - * @param dict - numbering dictionary - * @param lastLevel - last level - * @param numbering - boolean indicating whether to enable numbering - * @param numberingH1 - boolean indicating whether to enable first level headers numbering - * @param cellRef - cell reference - * @param index - index of referenced cell relative to other cells in the notebook - * @returns notebook heading - */ -function getRenderedHTMLHeadings( - node: HTMLElement, - onClick: onClickFactory, - sanitizer: ISanitizer, - dict: INumberingDictionary, - lastLevel: number, - numbering = false, - numberingH1 = true, - cellRef: Cell, - index: number = -1, - isRunning = RunningStatus.Idle -): INotebookHeading[] { - let nodes = node.querySelectorAll('h1, h2, h3, h4, h5, h6, p'); - - if (index === -1) { - console.warn( - 'Deprecation warning! index argument will become mandatory in the next version' - ); - } - let headings: INotebookHeading[] = []; - for (const el of Array.from(nodes)) { - if (el.classList.contains('jp-toc-ignore')) { - // skip this element if a special class name is included - continue; - } - if (el.nodeName.toLowerCase() === 'p') { - if (el.innerHTML) { - let html = sanitizer.sanitize(el.innerHTML, sanitizerOptions); - headings.push({ - level: lastLevel + 1, - html: html.replace('Âļ', ''), - text: el.textContent ? el.textContent : '', - onClick: onClick(el), - type: 'markdown', - cellRef: cellRef, - hasChild: false, - index: index, - isRunning - }); - } - continue; - } - if (el.getElementsByClassName('numbering-entry').length > 0) { - el.removeChild(el.getElementsByClassName('numbering-entry')[0]); - } - let html = sanitizer.sanitize(el.innerHTML, sanitizerOptions); - html = html.replace('Âļ', ''); - - let level = parseInt(el.tagName[1], 10); - if (!numberingH1) { - level -= 1; - } - let nstr = generateNumbering(dict, level); - if (numbering) { - const nhtml = document.createElement('span'); - nhtml.classList.add('numbering-entry'); - nhtml.textContent = nstr ?? ''; - el.insertBefore(nhtml, el.firstChild); - } - headings.push({ - level: level, - text: el.textContent ? el.textContent : '', - numbering: nstr, - html: html, - onClick: onClick(el), - type: 'header', - cellRef: cellRef, - hasChild: false, - index: index, - isRunning - }); - } - return headings; -} - -/** - * Exports. - */ -export { getRenderedHTMLHeadings }; diff --git a/packages/toc/src/generators/notebook/index.ts b/packages/toc/src/generators/notebook/index.ts deleted file mode 100644 index a5eed589aa28..000000000000 --- a/packages/toc/src/generators/notebook/index.ts +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { ISanitizer } from '@jupyterlab/apputils'; -import { - Cell, - CodeCell, - CodeCellModel, - ICellModel, - MARKDOWN_HEADING_COLLAPSED, - MarkdownCell -} from '@jupyterlab/cells'; -import { - INotebookTracker, - NotebookActions, - NotebookPanel -} from '@jupyterlab/notebook'; -import { ITranslator, nullTranslator } from '@jupyterlab/translation'; -import { TableOfContentsRegistry as Registry } from '../../registry'; -import { TableOfContents } from '../../toc'; -import { INotebookHeading } from '../../utils/headings'; -import { isDOM } from '../../utils/is_dom'; -import { isMarkdown } from '../../utils/is_markdown'; -import { appendHeading } from './append_heading'; -import { appendMarkdownHeading } from './append_markdown_heading'; -import { getCodeCellHeading } from './get_code_cell_heading'; -import { getLastHeadingLevel } from './get_last_heading_level'; -import { getMarkdownHeadings } from './get_markdown_heading'; -import { getRenderedHTMLHeadings } from './get_rendered_html_heading'; -import { OptionsManager } from './options_manager'; -import { render } from './render'; -import { toolbar } from './toolbar_generator'; -import { ISettingRegistry } from '@jupyterlab/settingregistry'; -import { ISignal } from '@lumino/signaling'; -import { RunningStatus } from '../../utils/headings'; -import { TableOfContentsRegistry } from '../../registry'; - -/** - * Returns a ToC generator for notebooks. - * - * @param tracker - notebook tracker - * @param widget - table of contents widget - * @param sanitizer - HTML sanitizer - * @param translator - Language translator - * @param settings - advanced settings for toc extension - * @returns ToC generator capable of parsing notebooks - */ -export function createNotebookGenerator( - tracker: INotebookTracker, - widget: TableOfContents, - sanitizer: ISanitizer, - translator?: ITranslator, - settings?: ISettingRegistry.ISettings -): Registry.IGenerator { - return new NotebookGenerator( - tracker, - widget, - sanitizer, - translator, - settings - ); -} - -class NotebookGenerator implements Registry.IGenerator { - /** - * Notebook Table of Content Generator constructor - * - * @param tracker - notebook tracker - * @param widget - table of contents widget - * @param sanitizer - HTML sanitizer - * @param translator - Language translator - * @param settings - advanced settings for toc extension - */ - constructor( - tracker: INotebookTracker, - widget: TableOfContents, - sanitizer: ISanitizer, - translator?: ITranslator, - settings?: ISettingRegistry.ISettings - ) { - this.sanitizer = sanitizer; - this.tracker = tracker; - this.widget = widget; - this._runningCells = new Array(); - - let numberingH1 = true; - let includeOutput = true; - let syncCollapseState = false; - if (settings) { - numberingH1 = settings.composite.numberingH1 as boolean; - includeOutput = settings.composite.includeOutput as boolean; - syncCollapseState = settings.composite.syncCollapseState as boolean; - } - const options = (this.options = new OptionsManager(widget, tracker, { - numbering: false, - numberingH1: numberingH1, - includeOutput: includeOutput, - syncCollapseState: syncCollapseState, - sanitizer: sanitizer, - translator: translator || nullTranslator - })); - if (settings) { - settings.changed.connect(() => { - options.numberingH1 = settings.composite.numberingH1 as boolean; - options.includeOutput = settings.composite.includeOutput as boolean; - options.syncCollapseState = settings.composite - .syncCollapseState as boolean; - }); - } - tracker.activeCellChanged.connect( - (sender: INotebookTracker, args: Cell) => { - widget.update(); - } - ); - NotebookActions.executionScheduled.connect((_, args) => { - if (!this._runningCells.includes(args.cell)) { - this._runningCells.push(args.cell); - } - }); - NotebookActions.executed.connect((_, args) => { - this._runningCells.forEach((cell, index) => { - if (cell === args.cell) { - this._runningCells.splice(index, 1); - } - }); - }); - } - - /** - * Signal to indicate that a collapse event happened to this heading - * within the ToC. - */ - get collapseChanged(): ISignal< - TableOfContentsRegistry.IOptionsManager, - TableOfContentsRegistry.ICollapseChangedArgs - > { - return this.options.collapseChanged; - } - - /** - * Returns a toolbar generator. - * - * @returns toolbar generator - */ - toolbarGenerator() { - return toolbar(this.options, this.tracker); - } - - /** - * Renders a table of contents item. - * - * @param item - heading to render - * @param toc - list of all headers to render - * @returns rendered item - */ - itemRenderer = ( - item: INotebookHeading, - toc: INotebookHeading[] = [] - ): JSX.Element | null => { - return render(this.options, this.tracker, this.widget, item, toc); - }; - - /** - * Generates a table of contents. - * - * @param panel - notebook widget - * @returns a list of headings - */ - generate(panel: NotebookPanel): INotebookHeading[] { - let headings: INotebookHeading[] = []; - let collapseLevel = -1; - let dict = {}; - - // Initialize a variable for keeping track of the previous heading: - let prev: INotebookHeading | null = null; - - // Generate headings by iterating through all notebook cells... - for (let i = 0; i < panel.content.widgets.length; i++) { - let cell: Cell = panel.content.widgets[i]; - let model = cell.model; - let cellCollapseMetadata = this.options.syncCollapseState - ? MARKDOWN_HEADING_COLLAPSED - : 'toc-hr-collapsed'; - const collapsed = - (model.metadata.get(cellCollapseMetadata) as boolean) ?? false; - - const isRunning = this._runningCells.includes(cell) - ? this._runningCells[0] === cell - ? RunningStatus.Running - : RunningStatus.Scheduled - : RunningStatus.Idle; - - switch (model.type) { - case 'code': { - if (!this.widget || (this.widget && this.options.showCode)) { - const onClick = (line: number) => { - return () => { - panel.content.activeCellIndex = i; - cell.node.scrollIntoView(); - }; - }; - const count = (cell as CodeCell).model.executionCount as - | number - | null; - const executionIndicator = - count ?? (isRunning !== RunningStatus.Idle ? '*' : ' '); - let executionCount = `[${executionIndicator}]: `; - let heading = getCodeCellHeading( - (model as CodeCellModel).value.text, - onClick, - executionCount, - getLastHeadingLevel(headings), - cell, - i, - isRunning - ); - [headings, prev] = appendHeading( - headings, - heading, - prev, - collapseLevel, - this.options.filtered - ); - } - if (this.options.includeOutput) { - // Iterate over the code cell outputs to check for Markdown or HTML from which we can generate ToC headings... - for (let j = 0; j < (model as CodeCellModel).outputs.length; j++) { - const m = (model as CodeCellModel).outputs.get(j); - - let dtypes = Object.keys(m.data); - dtypes = dtypes.filter(t => isMarkdown(t) || isDOM(t)); - if (!dtypes.length) { - continue; - } - const onClick = (el: Element) => { - return () => { - panel.content.activeCellIndex = i; - panel.content.mode = 'command'; - el.scrollIntoView(); - }; - }; - let htmlHeadings = getRenderedHTMLHeadings( - (cell as CodeCell).outputArea.widgets[j].node, - onClick, - this.sanitizer, - dict, - getLastHeadingLevel(headings), - this.options.numbering, - this.options.numberingH1, - cell, - i, - isRunning - ); - for (const heading of htmlHeadings) { - [headings, prev, collapseLevel] = appendMarkdownHeading( - heading, - headings, - prev, - collapseLevel, - this.options.filtered, - collapsed, - this.options.showMarkdown, - cellCollapseMetadata - ); - } - } - } - - break; - } - case 'markdown': { - let mcell = cell as MarkdownCell; - let heading: INotebookHeading | undefined; - let lastLevel = getLastHeadingLevel(headings); - - // If the cell is rendered, generate the ToC items from the HTML... - if (mcell.rendered && !mcell.inputHidden) { - const onClick = (el: Element) => { - return () => { - if (!mcell.rendered) { - panel.content.activeCellIndex = i; - el.scrollIntoView(); - } else { - panel.content.mode = 'command'; - cell.node.scrollIntoView(); - panel.content.activeCellIndex = i; - } - }; - }; - const htmlHeadings = getRenderedHTMLHeadings( - cell.node, - onClick, - this.sanitizer, - dict, - lastLevel, - this.options.numbering, - this.options.numberingH1, - cell, - i, - isRunning - ); - for (heading of htmlHeadings) { - [headings, prev, collapseLevel] = appendMarkdownHeading( - heading, - headings, - prev, - collapseLevel, - this.options.filtered, - collapsed, - this.options.showMarkdown, - cellCollapseMetadata - ); - } - // If not rendered, generate ToC items from the cell text... - } else { - const onClick = (line: number) => { - return () => { - panel.content.activeCellIndex = i; - cell.node.scrollIntoView(); - }; - }; - const markdownHeadings = getMarkdownHeadings( - model!.value.text, - onClick, - dict, - lastLevel, - cell, - i, - isRunning - ); - for (heading of markdownHeadings) { - [headings, prev, collapseLevel] = appendMarkdownHeading( - heading, - headings, - prev, - collapseLevel, - this.options.filtered, - collapsed, - this.options.showMarkdown, - cellCollapseMetadata - ); - } - } - - break; - } - } - - // Must be done afterwards as `heading.hasChild` needs to be up to date. - const lastHeading = headings[headings.length - 1]; - if (lastHeading) { - lastHeading.isRunning = Math.max(lastHeading.isRunning, isRunning); - } - } - return headings; - } - - /** - * Boolean indicating whether a document uses LaTeX typesetting. - */ - readonly usesLatex: true; - /** - * Options manager - */ - readonly options: OptionsManager; - /** - * Widget instance tracker. - */ - readonly tracker: INotebookTracker; - - protected readonly sanitizer: ISanitizer; - protected readonly widget: TableOfContents; - private _runningCells: Cell[]; -} diff --git a/packages/toc/src/generators/notebook/is_heading_filtered.ts b/packages/toc/src/generators/notebook/is_heading_filtered.ts deleted file mode 100644 index c79cfcbde4dc..000000000000 --- a/packages/toc/src/generators/notebook/is_heading_filtered.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { INotebookHeading } from '../../utils/headings'; - -/** - * Returns a boolean indicating whether a heading is filtered out by selected tags. - * - * @private - * @param heading - notebook heading - * @param tags - list of tags - * @returns boolean indicating whether a heading is filtered - */ -function isHeadingFiltered(heading: INotebookHeading, tags: string[]): boolean { - if (tags.length === 0) { - return false; - } - if (heading && heading.cellRef) { - let meta = heading.cellRef.model.metadata; - let ctags = meta.get('tags') as string[]; - if (ctags) { - for (let j = 0; j < ctags.length; j++) { - let name = ctags[j]; - for (let k = 0; k < tags.length; k++) { - if (tags[k] === name) { - return false; - } - } - } - } - } - return true; -} - -/** - * Exports. - */ -export { isHeadingFiltered }; diff --git a/packages/toc/src/generators/notebook/options_manager.ts b/packages/toc/src/generators/notebook/options_manager.ts deleted file mode 100644 index 34873ae45347..000000000000 --- a/packages/toc/src/generators/notebook/options_manager.ts +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { ISanitizer } from '@jupyterlab/apputils'; -import { INotebookTracker } from '@jupyterlab/notebook'; -import { ITranslator, nullTranslator } from '@jupyterlab/translation'; -import { ISignal, Signal } from '@lumino/signaling'; -import { TableOfContentsRegistry as Registry } from '../../registry'; -import { TableOfContents } from '../../toc'; -import { TagsToolComponent } from './tagstool'; - -/** - * Interface describing constructor options. - */ -interface IOptions { - /** - * Boolean indicating whether items should be numbered. - */ - numbering: boolean; - - /** - * Boolean indicating whether h1 headers should be numbered. - */ - numberingH1: boolean; - - /** - * Boolean indicating whether cell output should be included in headings. - */ - includeOutput: boolean; - /** - * Boolean indicating whether notebook headers should collapse with ToC headers and vice versa - */ - syncCollapseState: boolean; - /** - * HTML sanitizer. - */ - sanitizer: ISanitizer; - - /** - * Tag tool component. - */ - tagTool?: TagsToolComponent; - - /** - * The application language translator. - */ - translator?: ITranslator; -} - -/** - * Class for managing notebook ToC generator options. - * - * @private - */ -class OptionsManager implements Registry.IOptionsManager { - /** - * Returns an options manager. - * - * @param widget - table of contents widget - * @param notebook - notebook tracker - * @param options - generator options - * @returns options manager - */ - constructor( - widget: TableOfContents, - notebook: INotebookTracker, - options: IOptions - ) { - this._numbering = options.numbering; - this._numberingH1 = options.numberingH1; - this._includeOutput = options.includeOutput; - this._syncCollapseState = options.syncCollapseState; - this._widget = widget; - this._notebook = notebook; - this.sanitizer = options.sanitizer; - this.storeTags = []; - this.translator = options.translator || nullTranslator; - this._collapseChanged = new Signal( - this - ); - } - - /** - * HTML sanitizer. - */ - readonly sanitizer: ISanitizer; - - /** - * Gets/sets the tag tool component. - */ - set tagTool(tagTool: TagsToolComponent | null) { - this._tagTool = tagTool; - } - - get tagTool() { - return this._tagTool; - } - - /** - * Sets notebook meta data. - */ - set notebookMetadata(value: [string, any]) { - if (this._notebook.currentWidget != null) { - this._notebook.currentWidget.model!.metadata.set(value[0], value[1]); - } - } - - /** - * Gets/sets ToC generator numbering. - */ - set numbering(value: boolean) { - this._numbering = value; - this._widget.update(); - this.notebookMetadata = ['toc-autonumbering', this._numbering]; - } - - get numbering() { - return this._numbering; - } - - /** - * Gets/sets ToC generator numbering h1 headers. - */ - set numberingH1(value: boolean) { - if (this._numberingH1 != value) { - this._numberingH1 = value; - this._widget.update(); - } - } - - get numberingH1() { - return this._numberingH1; - } - - /** - * Toggles whether cell outputs should be included in headings. - */ - set includeOutput(value: boolean) { - if (this._includeOutput != value) { - this._includeOutput = value; - this._widget.update(); - } - } - - get includeOutput() { - return this._includeOutput; - } - /** - * Gets/sets option for ToC heading collapsing to be reflected in Notebook and vice versa - */ - set syncCollapseState(value: boolean) { - if (this._syncCollapseState != value) { - this._syncCollapseState = value; - this._widget.update(); - } - } - - get syncCollapseState() { - return this._syncCollapseState; - } - - /** - * Toggles whether to show code previews in the table of contents. - */ - set showCode(value: boolean) { - this._showCode = value; - this.notebookMetadata = ['toc-showcode', this._showCode]; - this._widget.update(); - } - - get showCode() { - return this._showCode; - } - - /** - * Toggles whether to show Markdown previews in the table of contents. - */ - set showMarkdown(value: boolean) { - this._showMarkdown = value; - this.notebookMetadata = ['toc-showmarkdowntxt', this._showMarkdown]; - this._widget.update(); - } - - get showMarkdown() { - return this._showMarkdown; - } - - /** - * Signal emitted when a "collapse" twist button is pressed in the ToC - */ - get collapseChanged(): ISignal { - return this._collapseChanged; - } - - /** - * Toggles whether to show tags in the table of contents. - */ - set showTags(value: boolean) { - this._showTags = value; - this.notebookMetadata = ['toc-showtags', this._showTags]; - this._widget.update(); - } - - get showTags() { - return this._showTags; - } - - /** - * Returns a list of selected tags. - */ - get filtered() { - if (this.tagTool) { - this._filtered = this.tagTool.filtered; - } else if (this.storeTags.length > 0) { - this._filtered = this.storeTags; - } else { - this._filtered = []; - } - return this._filtered; - } - - /** - * Gets/sets a pre-rendered a toolbar. - */ - set preRenderedToolbar(value: any) { - this._preRenderedToolbar = value; - } - - get preRenderedToolbar() { - return this._preRenderedToolbar; - } - - /** - * Updates a table of contents widget. - */ - updateWidget() { - this._widget.update(); - } - - /** - * Updates a table of contents widget and - * emits a signal in case an extension wants - * to perform an action when the collapse button - * is pressed. - */ - updateAndCollapse(args: Registry.ICollapseChangedArgs) { - this._collapseChanged.emit(args); - this._widget.update(); - } - - /** - * Initializes options. - * - * ## Notes - * - * - This will **not** change notebook meta-data. - * - * @param numbering - boolean indicating whether to number items - * @param numberingH1 - boolean indicating whether to number first level items - * @param includeOutput - boolean indicating whether cell outputs should be included in headings - * @param syncCollapseState - boolean indicating whether collapsing in ToC should be reflected in Notebook and vice versa - * @param showCode - boolean indicating whether to show code previews - * @param showMarkdown - boolean indicating whether to show Markdown previews - * @param showTags - boolean indicating whether to show tags - */ - initializeOptions( - numbering: boolean, - numberingH1: boolean, - includeOutput: boolean, - syncCollapseState: boolean, - showCode: boolean, - showMarkdown: boolean, - showTags: boolean - ) { - this._numbering = numbering; - this._numberingH1 = numberingH1; - this._includeOutput = includeOutput; - this._syncCollapseState = syncCollapseState; - this._showCode = showCode; - this._showMarkdown = showMarkdown; - this._showTags = showTags; - this._widget.update(); - } - - private _preRenderedToolbar: any = null; - private _filtered: string[] = []; - private _numbering: boolean; - private _numberingH1: boolean; - private _includeOutput: boolean; - private _syncCollapseState: boolean; - private _showCode = false; - private _showMarkdown = false; - private _showTags = false; - private _notebook: INotebookTracker; - private _widget: TableOfContents; - private _collapseChanged: Signal; - private _tagTool: TagsToolComponent | null = null; - translator: ITranslator; // FIXME-TRANS: - storeTags: string[]; -} - -/** - * Exports. - */ -export { OptionsManager }; diff --git a/packages/toc/src/generators/notebook/render.tsx b/packages/toc/src/generators/notebook/render.tsx deleted file mode 100644 index 44d888aad28f..000000000000 --- a/packages/toc/src/generators/notebook/render.tsx +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { MARKDOWN_HEADING_COLLAPSED } from '@jupyterlab/cells'; -import { INotebookTracker, NotebookActions } from '@jupyterlab/notebook'; -import { classes, ellipsesIcon } from '@jupyterlab/ui-components'; -import { ElementExt } from '@lumino/domutils'; -import * as React from 'react'; -import { TableOfContents } from '../..'; -import { INotebookHeading, RunningStatus } from '../../utils/headings'; -import { sanitizerOptions } from '../../utils/sanitizer_options'; -import { CodeComponent } from './codemirror'; -import { OptionsManager } from './options_manager'; - -/** - * Class name of the toc item list. - * - * @private - */ -const TOC_TREE_CLASS = 'jp-TableOfContents-content'; - -/** - * Renders a notebook table of contents item. - * - * @param options - generator options - * @param tracker - notebook tracker - * @param item - notebook heading - * @param toc - current list of notebook headings - * @returns rendered item - */ -export function render( - options: OptionsManager, - tracker: INotebookTracker, - widget: TableOfContents, - item: INotebookHeading, - toc: INotebookHeading[] = [] -): JSX.Element | null { - if (item.type === 'markdown' || item.type === 'header') { - const fontSizeClass = - item.type === 'header' - ? `toc-level-size-${item.level}` - : 'toc-level-size-default'; - const numbering = item.numbering && options.numbering ? item.numbering : ''; - const cellCollapseMetadata = options.syncCollapseState - ? MARKDOWN_HEADING_COLLAPSED - : 'toc-hr-collapsed'; - - if (item.type === 'header' || options.showMarkdown) { - const header = item.html ? ( - - ) : ( - - {numbering + item.text} - - ); - - if (item.type === 'header') { - let button = ( -
    { - event.stopPropagation(); - onClick(tracker, cellCollapseMetadata, item); - }} - > -
    -
    - ); - - let collapsed; - if (item.cellRef!.model.metadata.has(cellCollapseMetadata)) { - collapsed = item.cellRef!.model.metadata.get( - cellCollapseMetadata - ) as boolean; - } - let ellipseButton = collapsed ? ( -
    { - event.stopPropagation(); - onClick(tracker, cellCollapseMetadata, item); - }} - > - -
    - ) : null; - - return ( - - {button} - {header} - {ellipseButton} - - ); - } else { - return header; - } - } - } - - if (options.showCode && item.type === 'code') { - // Render code cells: - return ( -
    -
    {item.prompt}
    - - - -
    - ); - } - - return null; - - /** - * Callback invoked upon encountering a "click" event. - * - * @private - * @param heading - notebook heading that was clicked - */ - - function onClick( - tracker: INotebookTracker, - cellCollapseMetadata: string, - heading?: INotebookHeading - ) { - let collapsed = false; - let syncCollapseState = options.syncCollapseState; - if (heading!.cellRef!.model.metadata.get(cellCollapseMetadata)) { - collapsed = heading!.cellRef!.model.metadata.get( - cellCollapseMetadata - ) as boolean; - } - if (heading) { - if (syncCollapseState) { - // if collapse state is synced, update state here - if (tracker.currentWidget) { - NotebookActions.setHeadingCollapse( - heading!.cellRef!, - !collapsed, - tracker.currentWidget.content - ); - } - } else { - if (collapsed) { - heading!.cellRef!.model.metadata.delete(cellCollapseMetadata); - } else { - heading!.cellRef!.model.metadata.set(cellCollapseMetadata, true); - } - } - options.updateAndCollapse({ - heading: heading, - collapsedState: collapsed, - tocType: 'notebook' - }); - } else { - options.updateWidget(); - } - } -} - -/** - * Used to find the nearest above heading to an active notebook cell - * - * @private - * @param tracker - notebook tracker - * @param item - notebook heading - * @param toc - current list of notebook headings - * @returns true if heading is nearest above a selected cell, otherwise false - */ -function previousHeader( - tracker: INotebookTracker, - item: INotebookHeading, - toc: INotebookHeading[] -) { - if (item.index > -1 || toc?.length) { - let activeCellIndex = tracker.currentWidget!.content.activeCellIndex; - let headerIndex = item.index; - // header index has to be less than the active cell index - if (headerIndex < activeCellIndex) { - let tocIndexOfNextHeader = toc.indexOf(item) + 1; - // return true if header is the last header - if (tocIndexOfNextHeader >= toc.length) { - return true; - } - // return true if the next header cells index is greater than the active cells index - let nextHeaderIndex = toc?.[tocIndexOfNextHeader].index; - if (nextHeaderIndex > activeCellIndex) { - return true; - } - } - } - return false; -} - -type NotebookHeadingProps = React.PropsWithChildren<{ - isActive: boolean; - className: string; - area: Element | null; - isRunning?: RunningStatus; -}>; - -/** - * React component for a single toc heading - * - * @private - */ -function NotebookHeading(props: NotebookHeadingProps): JSX.Element { - const itemRef = React.useRef(null); - const isActive = props.isActive; - React.useEffect(() => { - if (isActive && itemRef.current && props.area) { - ElementExt.scrollIntoViewIfNeeded( - props.area, - itemRef.current.parentElement as Element - ); - } - }, [isActive]); - return ( -
    - {props.children} -
    - ); -} diff --git a/packages/toc/src/generators/notebook/tagstool/index.tsx b/packages/toc/src/generators/notebook/tagstool/index.tsx deleted file mode 100644 index bbf56ea77835..000000000000 --- a/packages/toc/src/generators/notebook/tagstool/index.tsx +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { Cell } from '@jupyterlab/cells'; -import { INotebookTracker } from '@jupyterlab/notebook'; -import { - ITranslator, - nullTranslator, - TranslationBundle -} from '@jupyterlab/translation'; -import * as React from 'react'; -import { OptionsManager } from '../options_manager'; -import { TagListComponent } from './tag_list'; - -/** - * Interface describing component properties. - * - * @private - */ -interface IProperties { - /** - * List of tags. - */ - tags: string[]; - - /** - * Notebook tracker. - */ - tracker: INotebookTracker; - - /** - * Notebook Generator options. - */ - options: OptionsManager; - - /** - * Input filter. - */ - inputFilter: string[]; - - /** - * Language translator. - */ - translator?: ITranslator; -} - -/** - * Interface describing component state. - * - * @private - */ -interface IState { - /** - * List of selected tags. - */ - selected: string[]; -} - -/** - * Tag dropdown React component. - * - * @private - */ -class TagsToolComponent extends React.Component { - /** - * Returns a component. - * - * @param props - component properties - * @returns component - */ - constructor(props: IProperties) { - super(props); - this.state = { - selected: this.props.inputFilter - }; - const translator = this.props.translator || nullTranslator; - this._trans = translator.load('jupyterlab'); - } - - /** - * Changes the dropdown selection state. - * - * @param newState - new state - * @param add - boolean indicating whether to add to selection - */ - changeSelectionState = (newState: string, add: boolean) => { - let tags = this.state.selected; - if (add) { - tags.push(newState); - this.setState({ selected: tags }); - this.filterTags(tags); - } else { - let selected: string[] = []; - for (let i = 0; i < tags.length; i++) { - if (tags[i] !== newState) { - selected.push(tags[i]); - } - } - this.setState({ selected: selected }); - this.filterTags(selected); - } - }; - - /** - * Returns a list of selected tags. - * - * @returns tag list - */ - get filtered() { - return this.state.selected; - } - - /** - * De-selects all tags in the dropdown and clear filters in the ToC. - */ - deselectAll = () => { - this.setState({ selected: [] }); - this.props.options.updateWidget(); - }; - - /** - * Checks whether a cell has a provided tag. - * - * @param tag - tag - * @param cell - cell reference - * @returns boolean indicating whether a cell has a provided tag - */ - containsTag(tag: string, cell: Cell) { - if (cell === null) { - return false; - } - let tagList = cell.model.metadata.get('tags') as string[]; - if (tagList) { - for (let i = 0; i < tagList.length; i++) { - if (tagList[i] === tag) { - return true; - } - } - return false; - } - } - - /** - * Select all the cells that contains all of the current tags and activates the first of those cells. - */ - - selectAllCellsWithCurrentTags = (): void => { - const tags = this.state.selected; - const panel = this.props.tracker.currentWidget; - const widgets = panel?.content.widgets; - - panel?.content.deselectAll(); - - let changedActive = false; - - widgets?.forEach((cell, ix) => { - const hasAllCurrentTags = tags.every(tag => this.containsTag(tag, cell)); - - if (hasAllCurrentTags) { - if (!changedActive) { - if (panel) { - panel.content.activeCellIndex = ix; - } - changedActive = true; - } - panel?.content.select(cell); - } - }); - }; - - /** - * Filters the ToC by according to selected tags. - * - * @param selected - selected tags - */ - filterTags = (selected: string[]) => { - this.setState({ selected }); - this.props.options.updateWidget(); - }; - - /** - * Updates filters. - */ - updateFilters = () => { - let tmp: string[] = []; - let idx = 0; - let update = false; - for (let i = 0; i < this.state.selected.length; i++) { - if (this.props.tags.indexOf(this.state.selected[i] as string) > -1) { - tmp[idx] = this.state.selected[i]; - idx += 1; - } else if (this.props.options.showTags === true) { - update = true; - } - } - if (update) { - this.filterTags(tmp); - this.setState({ selected: tmp }); - } - }; - - /** - * Updates filters. - */ - UNSAFE_componentWillUpdate() { - this.updateFilters(); - } - - /** - * Renders the interior of the tag dropdown. - * - * @returns rendered component - */ - render() { - let jsx = ( -
    - {this._trans.__('No Tags Available')} -
    - ); - let text; - if (this.state.selected.length === 0) { - text = ( - - {this._trans.__('Clear Filters')} - - ); - } else if (this.state.selected.length === 1) { - text = ( - this.deselectAll()} - > - {' '} - Clear 1 Filter{' '} - - ); - } else { - text = ( - this.deselectAll()} - > - {' '} - Clear {this.state.selected.length} Filters{' '} - - ); - } - let command; - - if (this.state.selected.length === 0) { - command = ( - - {this._trans.__('Select All Cells With Current Tags')} - - ); - } else { - command = ( - - {this._trans.__('Select All Cells With Current Tags')} - - ); - } - - if (this.props.tags && this.props.tags.length > 0) { - jsx = ( -
    - - {text} - {command} -
    - ); - } - return jsx; - } - - _trans: TranslationBundle; -} - -/** - * Exports. - */ -export { TagsToolComponent }; diff --git a/packages/toc/src/generators/notebook/tagstool/tag.tsx b/packages/toc/src/generators/notebook/tagstool/tag.tsx deleted file mode 100644 index 067e1505ae16..000000000000 --- a/packages/toc/src/generators/notebook/tagstool/tag.tsx +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import * as React from 'react'; - -/** - * Interface describing component properties. - * - * @private - */ -interface IProperties { - /** - * Selection state callback. - * - * @param newState - new state - * @param add - boolean flag - */ - selectionStateHandler: (newState: string, add: boolean) => void; - - /** - * Selected tags. - */ - selectedTags: string[]; - - /** - * Tag. - */ - tag: string; -} - -/** - * Abstract class defining a React component containing one tag label. - * - * @private - */ -abstract class TagComponent extends React.Component { - /** - * Returns a React component. - * - * @param props - properties - * @returns component - */ - constructor(props: IProperties) { - super(props); - } - - /** - * Renders a component. - * - * @returns rendered component - */ - render() { - const tag = this.props.tag as string; - return ( -
    - -
    - ); - } -} - -/** - * Exports. - */ -export { TagComponent }; diff --git a/packages/toc/src/generators/notebook/tagstool/tag_list.tsx b/packages/toc/src/generators/notebook/tagstool/tag_list.tsx deleted file mode 100644 index cb36182283f4..000000000000 --- a/packages/toc/src/generators/notebook/tagstool/tag_list.tsx +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import * as React from 'react'; -import { TagComponent } from './tag'; - -/** - * Interface describing component properties. - * - * @private - */ -interface IProperties { - /** - * Selection state handler. - * - * @param newState - new state - * @param add - boolean flag - */ - selectionStateHandler: (newState: string, add: boolean) => void; - - /** - * List of selected tags. - */ - selectedTags: string[]; - - /** - * List of all tags. - */ - tags: string[] | null; -} - -/** - * Interface describing component state. - * - * @private - */ -interface IState { - /** - * List of selected tags. - */ - selected: string[]; -} - -/** - * Class for a React component that renders all tags in a list. - * - * @private - */ -class TagListComponent extends React.Component { - /** - * Returns a React component. - * - * @param props - properties - * @returns component - */ - constructor(props: IProperties) { - super(props); - this.state = { selected: this.props.selectedTags }; - } - - /** - * Toggles whether a tag is selected when clicked. - * - * @param name - tag name - */ - selectedTagWithName = (name: string) => { - if (this.props.selectedTags.indexOf(name) >= 0) { - this.props.selectionStateHandler(name, false); - } else { - this.props.selectionStateHandler(name, true); - } - }; - - /** - * Renders a tag component for each tag within a list of tags. - * - * @param tags - list of tags - */ - renderTagComponents = (tags: string[]) => { - const selectedTags = this.props.selectedTags; - const selectedTagWithName = this.selectedTagWithName; - return tags.map((tag, index) => { - const tagClass = - selectedTags.indexOf(tag) >= 0 - ? 'toc-selected-tag toc-tag' - : 'toc-unselected-tag toc-tag'; - return ( -
    { - selectedTagWithName(tag); - }} - tabIndex={0} - > - -
    - ); - }); - }; - - /** - * Renders the list of tags in the ToC tags dropdown. - * - * @returns rendered list - */ - render() { - let tags = this.props.tags; - let jsx = null; - if (tags) { - jsx = this.renderTagComponents(tags); - } - return
    {jsx}
    ; - } -} - -/** - * Exports. - */ -export { TagListComponent }; diff --git a/packages/toc/src/generators/notebook/toolbar_generator.tsx b/packages/toc/src/generators/notebook/toolbar_generator.tsx deleted file mode 100644 index 6725ccb8b1ad..000000000000 --- a/packages/toc/src/generators/notebook/toolbar_generator.tsx +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { INotebookTracker } from '@jupyterlab/notebook'; -import { TranslationBundle } from '@jupyterlab/translation'; -import { - codeIcon, - markdownIcon, - numberingIcon, - tagIcon -} from '@jupyterlab/ui-components'; -import { JSONValue } from '@lumino/coreutils'; -import * as React from 'react'; -import { OptionsManager } from './options_manager'; -import { TagsToolComponent } from './tagstool'; - -/** - * Interface describing toolbar properties. - * - * @private - */ -interface IProperties {} - -/** - * Interface describing toolbar state. - * - * @private - */ -interface IState { - /** - * Boolean indicating whether to show code previews. - */ - showCode: boolean; - - /** - * Boolean indicating whether to show Markdown previews. - */ - showMarkdown: boolean; - - /** - * Boolean indicating whether to show tags. - */ - showTags: boolean; - - /** - * Boolean indicating whether to show numbering. - */ - numbering: boolean; -} - -/** - * Returns a component for rendering a notebook table of contents toolbar. - * - * @private - * @param options - generator options - * @param tracker - notebook tracker - * @returns toolbar component - */ -function toolbar(options: OptionsManager, tracker: INotebookTracker) { - return class Toolbar extends React.Component { - /** - * Returns a component for rendering a notebook table of contents toolbar. - * - * @param props - toolbar properties - * @returns toolbar component - */ - constructor(props: IProperties) { - super(props); - this._trans = options.translator.load('jupyterlab'); - this.tagTool = null; - this.state = { - showCode: true, - showMarkdown: false, - showTags: false, - numbering: false - }; - if (tracker.currentWidget) { - // Read saved user settings in notebook meta data: - void tracker.currentWidget.context.ready.then(() => { - if (tracker.currentWidget) { - tracker.currentWidget.content.activeCellChanged.connect(() => { - options.updateWidget(); - }); - const numbering = tracker.currentWidget.model!.metadata.get( - 'toc-autonumbering' - ) as boolean; - const showCode = tracker.currentWidget.model!.metadata.get( - 'toc-showcode' - ) as boolean; - const showMarkdown = tracker.currentWidget.model!.metadata.get( - 'toc-showmarkdowntxt' - ) as boolean; - const showTags = tracker.currentWidget.model!.metadata.get( - 'toc-showtags' - ) as boolean; - options.initializeOptions( - numbering || options.numbering, - options.numberingH1, - options.includeOutput, - options.syncCollapseState, - showCode || options.showCode, - showMarkdown || options.showMarkdown, - showTags || options.showTags - ); - this.setState({ - showCode: options.showCode, - showMarkdown: options.showMarkdown, - showTags: options.showTags, - numbering: options.numbering - }); - this.tags = []; - } - }); - } - } - - /** - * Toggle whether to show code previews. - */ - toggleCode() { - options.showCode = !options.showCode; - this.setState({ showCode: options.showCode }); - } - - /** - * Toggle whether to show Markdown previews. - */ - toggleMarkdown() { - options.showMarkdown = !options.showMarkdown; - this.setState({ showMarkdown: options.showMarkdown }); - } - - /** - * Toggle whether to number headings. - */ - toggleNumbering() { - options.numbering = !options.numbering; - this.setState({ numbering: options.numbering }); - } - - /** - * Toggle tag dropdown. - */ - toggleTagDropdown() { - if (options.showTags && this.tagTool) { - options.storeTags = this.tagTool.state.selected; - } - options.showTags = !options.showTags; - this.setState({ showTags: options.showTags }); - } - - /** - * Loads all document tags. - */ - loadTags() { - const notebook = tracker.currentWidget; - if (notebook) { - const cells = notebook.model!.cells; - const tags = new Set(); - this.tags = []; - for (let i = 0; i < cells.length; i++) { - const cell = cells.get(i)!; - const list = cell.metadata.get('tags') as JSONValue; - if (Array.isArray(list)) { - list.forEach((tag: string) => tag && tags.add(tag)); - } - } - this.tags = Array.from(tags); - } - } - - /** - * Renders a toolbar. - * - * @returns rendered toolbar - */ - render() { - const codeToggleIcon = ( -
    this.toggleCode()} - role="text" - aria-label={this._trans.__('Toggle Code Cells')} - title={this._trans.__('Toggle Code Cells')} - className={ - this.state.showCode - ? 'toc-toolbar-code-icon toc-toolbar-icon-selected' - : 'toc-toolbar-code-icon toc-toolbar-icon' - } - > - -
    - ); - - const markdownToggleIcon = ( -
    this.toggleMarkdown()} - role="text" - aria-label={this._trans.__('Toggle Markdown Text Cells')} - title={this._trans.__('Toggle Markdown Text Cells')} - className={ - this.state.showMarkdown - ? 'toc-toolbar-icon-selected' - : 'toc-toolbar-icon' - } - > - -
    - ); - - const numberingToggleIcon = ( -
    this.toggleNumbering()} - role="text" - aria-label={this._trans.__('Toggle Auto-Numbering')} - title={this._trans.__('Toggle Auto-Numbering')} - className={ - this.state.numbering - ? 'toc-toolbar-icon-selected' - : 'toc-toolbar-icon' - } - > - -
    - ); - - let tagDropdown =
    ; - let tagToggleIcon = ( -
    - -
    - ); - if (this.state.showTags) { - this.loadTags(); - const tagTool = ( - (this.tagTool = tagTool)} - /> - ); - options.tagTool = this.tagTool; - tagDropdown =
    {tagTool}
    ; - } - - return ( -
    -
    - {codeToggleIcon} - {markdownToggleIcon} - {numberingToggleIcon} -
    this.toggleTagDropdown()} - > - {tagToggleIcon} -
    -
    - {tagDropdown} -
    - ); - } - - /** - * List of tags. - */ - tags: string[]; - - /** - * Tag tool component. - */ - tagTool: TagsToolComponent | null; - - /** - * Translation bundle. - */ - _trans: TranslationBundle; - }; -} - -/** - * Exports. - */ -export { toolbar }; diff --git a/packages/toc/src/generators/python/index.ts b/packages/toc/src/generators/python/index.ts deleted file mode 100644 index a1d327911975..000000000000 --- a/packages/toc/src/generators/python/index.ts +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { IDocumentWidget } from '@jupyterlab/docregistry'; -import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor'; -import { TableOfContentsRegistry as Registry } from '../../registry'; -import { IHeading } from '../../utils/headings'; -import { render } from './render'; - -/** - * Generates a table of contents. - * - * @private - * @param editor - editor widget - * @returns a list of headings - */ -function generate(editor: IDocumentWidget): IHeading[] { - // Split the text into lines: - let lines = editor.content.model.value.text.split('\n') as Array; - - // Iterate over the lines to get the heading level and text for each line: - let headings: IHeading[] = []; - let processingImports = false; - for (let i = 0; i < lines.length; i++) { - let line = lines[i].trim(); - if (line.indexOf('def ') === 0) { - processingImports = false; - headings.push({ - text: line.slice(0, -1), - level: 2, - onClick: onClick(i) - }); - } else if (line.indexOf('class ') === 0) { - processingImports = false; - headings.push({ - text: line.slice(0, -1), - level: 1, - onClick: onClick(i) - }); - } else if (line.indexOf('import ') == 0 && !processingImports) { - processingImports = true; - headings.push({ - text: line, - level: 2, - onClick: onClick(i) - }); - } - } - return headings; - - /** - * Returns a "click" handler. - * - * @private - * @param line - line number - * @returns click handler - */ - function onClick(line: number) { - return () => { - editor.content.editor.setCursorPosition({ - line: line, - column: 0 - }); - }; - } -} - -/** - * Returns a boolean indicating whether this ToC generator is enabled. - * - * @private - * @param editor - editor widget - * @returns boolean indicating whether this ToC generator is enabled - */ -function isEnabled(editor: IDocumentWidget) { - let mime = editor.content.model.mimeType; - return mime === 'application/x-python-code' || mime === 'text/x-python'; -} - -/** - * Returns a ToC generator for Python files. - * - * @private - * @param tracker - file editor tracker - * @returns ToC generator capable of parsing Python files - */ -function createPythonGenerator( - tracker: IEditorTracker -): Registry.IGenerator> { - return { - tracker, - isEnabled: isEnabled, - itemRenderer: render, - generate: generate - }; -} - -/** - * Exports. - */ -export { createPythonGenerator }; diff --git a/packages/toc/src/generators/python/render.tsx b/packages/toc/src/generators/python/render.tsx deleted file mode 100644 index 761707d5c49a..000000000000 --- a/packages/toc/src/generators/python/render.tsx +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import * as React from 'react'; -import { IHeading } from '../../utils/headings'; - -/** - * Renders a Python table of contents item. - * - * @private - * @param item - numbered heading - * @returns rendered item - */ -function render(item: IHeading) { - let fontSizeClass = 'toc-level-size-' + item.level; - - return ( -
    -
    -
    -
    - {item.text} -
    - ); -} - -/** - * Exports. - */ -export { render }; diff --git a/packages/toc/src/index.ts b/packages/toc/src/index.ts index 076d4940ae09..9312542d8a55 100644 --- a/packages/toc/src/index.ts +++ b/packages/toc/src/index.ts @@ -5,9 +5,14 @@ * @module toc */ -// Note: keep in alphabetical order... -export * from './generators'; +export * from './factory'; +export * from './model'; +export * from './panel'; export * from './registry'; -export * from './toc'; -export * from './toc_item'; -export * from './utils/headings'; +export * from './treeview'; +export * from './tocitem'; +export * from './toctree'; +export * from './tokens'; +export * from './tracker'; +// Namespace the utils +export * as TableOfContentsUtils from './utils'; diff --git a/packages/toc/src/model.ts b/packages/toc/src/model.ts new file mode 100644 index 000000000000..7f196401e860 --- /dev/null +++ b/packages/toc/src/model.ts @@ -0,0 +1,288 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { VDomModel } from '@jupyterlab/ui-components'; +import { JSONExt } from '@lumino/coreutils'; +import { ISignal, Signal } from '@lumino/signaling'; +import { Widget } from '@lumino/widgets'; +import { TableOfContents } from './tokens'; + +/** + * Abstract table of contents model. + */ +export abstract class TableOfContentsModel< + H extends TableOfContents.IHeading, + T extends Widget = Widget + > + extends VDomModel + implements TableOfContents.IModel +{ + /** + * Constructor + * + * @param widget The widget to search in + * @param configuration Default model configuration + */ + constructor( + protected widget: T, + configuration?: TableOfContents.IConfig + ) { + super(); + this._activeHeading = null; + this._activeHeadingChanged = new Signal< + TableOfContentsModel, + H | null + >(this); + this._collapseChanged = new Signal, H>(this); + this._configuration = configuration ?? { ...TableOfContents.defaultConfig }; + this._headings = new Array(); + this._headingsChanged = new Signal, void>(this); + this._isActive = false; + this._isRefreshing = false; + this._needsRefreshing = false; + } + + /** + * Current active entry. + * + * @returns table of contents active entry + */ + get activeHeading(): H | null { + return this._activeHeading; + } + + /** + * Signal emitted when the active heading changes. + */ + get activeHeadingChanged(): ISignal, H | null> { + return this._activeHeadingChanged; + } + + /** + * Signal emitted when a table of content section collapse state changes. + */ + get collapseChanged(): ISignal, H | null> { + return this._collapseChanged; + } + + /** + * Model configuration + */ + get configuration(): TableOfContents.IConfig { + return this._configuration; + } + + /** + * Type of document supported by the model. + * + * #### Notes + * A `data-document-type` attribute with this value will be set + * on the tree view `.jp-TableOfContents-content[data-document-type="..."]` + */ + abstract readonly documentType: string; + + /** + * List of headings. + * + * @returns table of contents list of headings + */ + get headings(): H[] { + return this._headings; + } + + /** + * Signal emitted when the headings changes. + */ + get headingsChanged(): ISignal, void> { + return this._headingsChanged; + } + + /** + * Whether the model is active or not. + * + * #### Notes + * An active model means it is displayed in the table of contents. + * This can be used by subclass to limit updating the headings. + */ + get isActive(): boolean { + return this._isActive; + } + set isActive(v: boolean) { + this._isActive = v; + // Refresh on activation expect if it is always active + // => a ToC model is always active e.g. when displaying numbering in the document + if (this._isActive && !this.isAlwaysActive) { + this.refresh().catch(reason => { + console.error('Failed to refresh ToC model.', reason); + }); + } + } + + /** + * Whether the model gets updated even if the table of contents panel + * is hidden or not. + * + * #### Notes + * For example, ToC models use to add title numbering will + * set this to true. + */ + protected get isAlwaysActive(): boolean { + return false; + } + + /** + * List of configuration options supported by the model. + */ + get supportedOptions(): (keyof TableOfContents.IConfig)[] { + return ['maximalDepth']; + } + + /** + * Document title + */ + get title(): string | undefined { + return this._title; + } + set title(v: string | undefined) { + if (v !== this._title) { + this._title = v; + this.stateChanged.emit(); + } + } + + /** + * Abstract function that will produce the headings for a document. + * + * @returns The list of new headings or `null` if nothing needs to be updated. + */ + protected abstract getHeadings(): Promise; + + /** + * Refresh the headings list. + */ + async refresh(): Promise { + if (this._isRefreshing) { + // Schedule a refresh if one is in progress + this._needsRefreshing = true; + return Promise.resolve(); + } + + this._isRefreshing = true; + try { + const newHeadings = await this.getHeadings(); + + if (this._needsRefreshing) { + this._needsRefreshing = false; + this._isRefreshing = false; + return this.refresh(); + } + + if ( + newHeadings && + !Private.areHeadingsEqual(newHeadings, this._headings) + ) { + this._headings = newHeadings; + this.stateChanged.emit(); + this._headingsChanged.emit(); + } + } finally { + this._isRefreshing = false; + } + } + + /** + * Set a new active heading. + * + * @param heading The new active heading + * @param emitSignal Whether to emit the activeHeadingChanged signal or not. + */ + setActiveHeading(heading: H | null, emitSignal = true): void { + if (this._activeHeading !== heading) { + this._activeHeading = heading; + this.stateChanged.emit(); + if (emitSignal) { + this._activeHeadingChanged.emit(heading); + } + } + } + + /** + * Model configuration setter. + * + * @param c New configuration + */ + setConfiguration(c: Partial): void { + const newConfiguration = { ...this._configuration, ...c }; + if (!JSONExt.deepEqual(this._configuration, newConfiguration)) { + this._configuration = newConfiguration as TableOfContents.IConfig; + this.refresh().catch(reason => { + console.error('Failed to update the table of contents.', reason); + }); + } + } + + /** + * Callback on heading collapse. + * + * @param options.heading The heading to change state (all headings if not provided) + * @param options.collapsed The new collapsed status (toggle existing status if not provided) + */ + toggleCollapse(options: { heading?: H; collapsed?: boolean }): void { + if (options.heading) { + options.heading.collapsed = + options.collapsed ?? !options.heading.collapsed; + this.stateChanged.emit(); + this._collapseChanged.emit(options.heading); + } else { + // Use the provided state or collapsed all except if all are collapsed + const newState = + options.collapsed ?? !this.headings.some(h => !(h.collapsed ?? false)); + this.headings.forEach(h => (h.collapsed = newState)); + this.stateChanged.emit(); + this._collapseChanged.emit(null); + } + } + + private _activeHeading: H | null; + private _activeHeadingChanged: Signal, H | null>; + private _collapseChanged: Signal, H | null>; + private _configuration: TableOfContents.IConfig; + private _headings: H[]; + private _headingsChanged: Signal, void>; + private _isActive: boolean; + private _isRefreshing: boolean; + private _needsRefreshing: boolean; + private _title?: string; +} + +/** + * Private functions namespace + */ +namespace Private { + /** + * Test if two list of headings are equal or not. + * + * @param headings1 First list of headings + * @param headings2 Second list of headings + * @returns Whether the array are identical or not. + */ + export function areHeadingsEqual( + headings1: TableOfContents.IHeading[], + headings2: TableOfContents.IHeading[] + ): boolean { + if (headings1.length === headings2.length) { + for (let i = 0; i < headings1.length; i++) { + if ( + headings1[i].level !== headings2[i].level || + headings1[i].text !== headings2[i].text || + headings1[i].prefix !== headings2[i].prefix + ) { + return false; + } + } + return true; + } + + return false; + } +} diff --git a/packages/toc/src/panel.ts b/packages/toc/src/panel.ts new file mode 100644 index 000000000000..906524e41bb7 --- /dev/null +++ b/packages/toc/src/panel.ts @@ -0,0 +1,118 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { ITranslator } from '@jupyterlab/translation'; +import { SidePanel } from '@jupyterlab/ui-components'; +import { Panel, Widget } from '@lumino/widgets'; +import { TableOfContentsWidget } from './treeview'; +import { TableOfContents } from './tokens'; +import { Message } from '@lumino/messaging'; + +/** + * Table of contents sidebar panel. + */ +export class TableOfContentsPanel extends SidePanel { + /** + * Constructor + * + * @param translator - Translator tool + */ + constructor(translator?: ITranslator) { + super({ content: new Panel(), translator }); + this._model = null; + + this.addClass('jp-TableOfContents'); + + this._title = new Private.Header(this._trans.__('Table of Contents')); + this.header.addWidget(this._title); + + this._treeview = new TableOfContentsWidget({ + placeholderHeadline: this._trans.__('No Headings'), + placeholderText: this._trans.__( + 'The table of contents shows headings in notebooks and supported files.' + ) + }); + this._treeview.addClass('jp-TableOfContents-tree'); + this.content.addWidget(this._treeview); + } + + /** + * Get the current model. + */ + get model(): TableOfContents.Model | null { + return this._model; + } + set model(newValue: TableOfContents.Model | null) { + if (this._model !== newValue) { + this._model?.stateChanged.disconnect(this._onTitleChanged, this); + + this._model = newValue; + if (this._model) { + this._model.isActive = this.isVisible; + } + + this._model?.stateChanged.connect(this._onTitleChanged, this); + this._onTitleChanged(); + + this._treeview.model = this._model; + } + } + + protected onAfterHide(msg: Message): void { + super.onAfterHide(msg); + if (this._model) { + this._model.isActive = false; + } + } + + protected onBeforeShow(msg: Message): void { + super.onBeforeShow(msg); + if (this._model) { + this._model.isActive = true; + } + } + + private _onTitleChanged(): void { + this._title.setTitle( + this._model?.title ?? this._trans.__('Table of Contents') + ); + } + + private _model: TableOfContents.Model | null; + private _title: Private.Header; + private _treeview: TableOfContentsWidget; +} + +/** + * Private helpers namespace + */ +namespace Private { + /** + * Panel header + */ + export class Header extends Widget { + /** + * Constructor + * + * @param title - Title text + */ + constructor(title: string) { + const node = document.createElement('h2'); + node.textContent = title; + node.classList.add('jp-text-truncated'); + super({ node }); + this._title = node; + } + + /** + * Set the header title. + */ + setTitle(title: string): void { + this._title.textContent = title; + } + + private _title: HTMLElement; + } +} diff --git a/packages/toc/src/registry.ts b/packages/toc/src/registry.ts index efe96afd04eb..7bb5156994c1 100644 --- a/packages/toc/src/registry.ts +++ b/packages/toc/src/registry.ts @@ -1,50 +1,32 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IWidgetTracker } from '@jupyterlab/apputils'; -import { Token } from '@lumino/coreutils'; -import { ISignal, Signal } from '@lumino/signaling'; +import { DisposableDelegate, IDisposable } from '@lumino/disposable'; import { Widget } from '@lumino/widgets'; -import { IHeading, INotebookHeading } from './utils/headings'; +import { ITableOfContentsRegistry, TableOfContents } from './tokens'; /** - * Interface describing the table of contents registry. - * - * @private + * Class for registering table of contents generators. */ -export interface ITableOfContentsRegistry extends TableOfContentsRegistry {} - -/* tslint:disable */ -/** - * Table of contents registry token. - */ -export const ITableOfContentsRegistry = new Token( - '@jupyterlab/toc:ITableOfContentsRegistry' -); -/* tslint:enable */ - -/** - * Class for registering widgets for which we can generate a table of contents. - */ -export class TableOfContentsRegistry { +export class TableOfContentsRegistry implements ITableOfContentsRegistry { /** - * Finds a table of contents generator for a widget. + * Finds a table of contents model for a widget. * * ## Notes * - * - If unable to find a table of contents generator, the method return `undefined`. + * - If unable to find a table of contents model, the method return `undefined`. * * @param widget - widget - * @returns table of contents generator + * @param configuration - Default model configuration + * @returns Table of contents model */ - find(widget: Widget): TableOfContentsRegistry.IGenerator | undefined { - for (let i = 0; i < this._generators.length; i++) { - const gen = this._generators[i]; - if (gen.tracker.has(widget)) { - if (gen.isEnabled && !gen.isEnabled(widget)) { - continue; - } - return gen; + getModel( + widget: Widget, + configuration?: TableOfContents.IConfig + ): TableOfContents.Model | undefined { + for (const generator of this._generators.values()) { + if (generator.isApplicable(widget)) { + return generator.createNew(widget, configuration); } } } @@ -54,139 +36,15 @@ export class TableOfContentsRegistry { * * @param generator - table of contents generator */ - add(generator: TableOfContentsRegistry.IGenerator): void { - if (generator.collapseChanged) { - // If there is a collapseChanged for a given generator, propagate the arguments through the registry's signal - generator.collapseChanged.connect( - ( - sender: TableOfContentsRegistry.IGenerator, - args: TableOfContentsRegistry.ICollapseChangedArgs - ) => { - this._collapseChanged.emit(args); - } - ); - } - this._generators.push(generator); - } + add(generator: TableOfContents.IFactory): IDisposable { + const id = this._idCounter++; + this._generators.set(id, generator); - get collapseChanged(): ISignal< - this, - TableOfContentsRegistry.ICollapseChangedArgs - > { - return this._collapseChanged; + return new DisposableDelegate(() => { + this._generators.delete(id); + }); } - private _collapseChanged: Signal< - this, - TableOfContentsRegistry.ICollapseChangedArgs - > = new Signal(this); - private _generators: TableOfContentsRegistry.IGenerator[] = []; -} - -/** - * Static registry methods. - */ -export namespace TableOfContentsRegistry { - /** - * Abstract class for managing options affecting how a table of contents is generated for a particular widget type. - */ - export interface IOptionsManager {} - - /** - * Interface for the arguments needed in the collapse signal of a generator - */ - export interface ICollapseChangedArgs { - /** - * Boolean indicating whether the given heading is collapsed in ToC - */ - collapsedState: boolean; - - /** - * Heading that was involved in the collapse event - */ - heading: IHeading; - - /** - * Type of file that the given heading was produced from - */ - tocType: string; - } - - /** - * Interface describing a widget table of contents generator. - */ - export interface IGenerator { - /** - * Widget instance tracker. - */ - tracker: IWidgetTracker; - - /** - * Returns a boolean indicating whether we can generate a ToC for a widget. - * - * ## Notes - * - * - By default, we assume ToC generation is enabled if the widget is hosted in `tracker`. - * - However, a user may want to add additional checks (e.g., only generate a ToC for text files only if they have a given MIME type). - * - * @param widget - widget - * @returns boolean indicating whether we can generate a ToC for a widget - */ - isEnabled?: (widget: W) => boolean; - - /** - * Boolean indicating whether a document uses LaTeX typesetting. - * - * @default false - */ - usesLatex?: boolean; - - /** - * Options manager. - * - * @default undefined - */ - options?: IOptionsManager; - - /** - * Signal to indicate that a collapse event happened to this heading - * within the ToC. - */ - collapseChanged?: ISignal; - - /** - * Returns a JSX element for each heading. - * - * ## Notes - * - * - If not present, a default renderer will be used. - * - * @param item - heading - * @param toc - list of headings - * @returns JSX element - */ - itemRenderer?: ( - item: IHeading, - toc: INotebookHeading[] - ) => JSX.Element | null; - - /** - * Returns a toolbar component. - * - * ## Notes - * - * - If not present, no toolbar is generated. - * - * @returns toolbar component - */ - toolbarGenerator?: () => any; - - /** - * Returns a list of headings. - * - * @param widget - widget - * @returns list of headings - */ - generate(widget: W, options?: IOptionsManager): IHeading[]; - } + private _generators = new Map(); + private _idCounter = 0; } diff --git a/packages/toc/src/toc.tsx b/packages/toc/src/toc.tsx deleted file mode 100644 index 2d9ec10748a4..000000000000 --- a/packages/toc/src/toc.tsx +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { ActivityMonitor, PathExt } from '@jupyterlab/coreutils'; -import { IDocumentManager } from '@jupyterlab/docmanager'; -import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; -import { - ITranslator, - nullTranslator, - TranslationBundle -} from '@jupyterlab/translation'; -import { Message } from '@lumino/messaging'; -import { Widget } from '@lumino/widgets'; -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; -import { IHeading } from './utils/headings'; -import { TableOfContentsRegistry as Registry } from './registry'; -import { TOCTree } from './toc_tree'; -import { Signal } from '@lumino/signaling'; -import { TOCItem } from './toc_item'; - -/** - * Timeout for throttling ToC rendering. - * - * @private - */ -const RENDER_TIMEOUT = 1000; - -/** - * Widget for hosting a notebook table of contents. - */ -export class TableOfContents extends Widget { - /** - * Returns a new table of contents. - * - * @param options - options - * @returns widget - */ - constructor(options: TableOfContents.IOptions) { - super(); - this.translator = options.translator || nullTranslator; - this._docmanager = options.docmanager; - this._rendermime = options.rendermime; - this._trans = this.translator.load('jupyterlab'); - this._headings = []; - this._entryClicked = new Signal(this); - this._entryClicked.connect((toc, item) => { - this.activeEntry = item.props.heading; - }); - if (this._current) { - this._headings = this._current.generator.generate( - this._current.widget, - this._current.generator.options - ); - } - } - - /** - * Current widget-generator tuple for the ToC. - */ - get current(): TableOfContents.ICurrentWidget | null { - return this._current; - } - set current(value: TableOfContents.ICurrentWidget | null) { - // If they are the same as previously, do nothing... - if ( - value && - this._current && - this._current.widget === value.widget && - this._current.generator === value.generator - ) { - return; - } - this._current = value; - - if (this.generator) { - if (this.generator.toolbarGenerator) { - this._toolbar = this.generator.toolbarGenerator(); - } else { - this._toolbar = null; - } - } - // Dispose an old activity monitor if one existed... - if (this._monitor) { - this._monitor.dispose(); - this._monitor = null; - } - // If we are wiping the ToC, update and return... - if (!this._current) { - this.update(); - return; - } - // Find the document model associated with the widget: - const context = this._docmanager.contextForWidget(this._current.widget); - if (!context || !context.model) { - throw Error('Could not find a context for the Table of Contents'); - } - // Throttle the rendering rate of the table of contents: - this._monitor = new ActivityMonitor({ - signal: context.model.contentChanged, - timeout: RENDER_TIMEOUT - }); - this._monitor.activityStopped.connect(this.update, this); - this.update(); - } - - /** - * Current table of contents generator. - * - * @returns table of contents generator - */ - get generator() { - if (this._current) { - return this._current.generator; - } - return null; - } - - /** - * Callback invoked upon an update request. - * - * @param msg - message - */ - protected onUpdateRequest(msg: Message): void { - if (this.isHidden) { - // Bail early - return; - } - - let title = this._trans.__('Table of Contents'); - if (this._current) { - this._headings = this._current.generator.generate( - this._current.widget, - this._current.generator.options - ); - const context = this._docmanager.contextForWidget(this._current.widget); - if (context) { - title = PathExt.basename(context.localPath); - } - } - let itemRenderer: ( - item: IHeading, - toc: IHeading[] - ) => JSX.Element | null = (item: IHeading) => { - return {item.text}; - }; - if (this._current && this._current.generator.itemRenderer) { - itemRenderer = this._current.generator.itemRenderer!; - } - let jsx = ( -
    -
    {title}
    -
    - ); - if (this._current && this._current.generator) { - jsx = ( - - ); - } - ReactDOM.render(jsx, this.node, () => { - if ( - this._current && - this._current.generator.usesLatex === true && - this._rendermime.latexTypesetter - ) { - this._rendermime.latexTypesetter.typeset(this.node); - } - }); - } - - /** - * Current active entry. - * - * @returns table of contents active entry - */ - get activeEntry(): IHeading { - return this._activeEntry; - } - - set activeEntry(value: IHeading) { - this._activeEntry = value; - } - - /** - * List of headings. - * - * @returns table of contents list of headings - */ - get headings(): IHeading[] { - return this._headings; - } - - /** - * Callback invoked to re-render after showing a table of contents. - * - * @param msg - message - */ - protected onAfterShow(msg: Message): void { - this.update(); - } - - private translator: ITranslator; - private _activeEntry: IHeading; - private _entryClicked?: Signal; - private _trans: TranslationBundle; - private _toolbar: any; - private _rendermime: IRenderMimeRegistry; - private _docmanager: IDocumentManager; - private _current: TableOfContents.ICurrentWidget | null; - private _monitor: ActivityMonitor | null; - private _headings: IHeading[]; -} - -/** - * A namespace for TableOfContents statics. - */ -export namespace TableOfContents { - /** - * Interface describing table of contents widget options. - */ - export interface IOptions { - /** - * Application document manager. - */ - docmanager: IDocumentManager; - - /** - * Application rendered MIME type. - */ - rendermime: IRenderMimeRegistry; - - /** - * Application language translator. - */ - translator?: ITranslator; - } - - /** - * Interface describing the current widget. - */ - export interface ICurrentWidget { - /** - * Current widget. - */ - widget: W; - - /** - * Table of contents generator for the current widget. - */ - generator: Registry.IGenerator; - } -} diff --git a/packages/toc/src/toc_item.tsx b/packages/toc/src/toc_item.tsx deleted file mode 100644 index 068a25d5260c..000000000000 --- a/packages/toc/src/toc_item.tsx +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import * as React from 'react'; -import { IHeading } from './utils/headings'; -import { Signal } from '@lumino/signaling'; -import { TableOfContents } from './toc'; - -/** - * Interface describing component properties. - * - * @private - */ -interface IProperties { - /** - * Heading to render. - */ - heading: IHeading; - /** - * List of headings to use for rendering current position in toc - */ - toc: IHeading[]; - - /** - * Optional signal that emits when a toc entry is clicked - */ - entryClicked?: Signal; - - /** - * Renders a heading. - * - * @param item - heading - * @param toc - list of headings - * @returns rendered heading - */ - itemRenderer: (item: IHeading, toc: IHeading[]) => JSX.Element | null; -} - -/** - * Interface describing component state. - * - * @private - */ -interface IState {} - -/** - * React component for a table of contents entry. - * - * @private - */ -class TOCItem extends React.Component { - /** - * Renders a table of contents entry. - * - * @returns rendered entry - */ - render() { - const { heading, toc } = this.props; - - // Create an onClick handler for the TOC item - // that scrolls the anchor into view. - const onClick = (event: React.SyntheticEvent) => { - event.preventDefault(); - event.stopPropagation(); - this.props.entryClicked?.emit(this); - heading.onClick(); - }; - - let content = this.props.itemRenderer(heading, toc); - if (!content) { - return null; - } - return ( -
  • ) => { - this.props.entryClicked?.emit(this); - heading.onClick(); - }} - > - {content} -
  • - ); - } -} - -/** - * Exports. - */ -export { TOCItem }; diff --git a/packages/toc/src/toc_tree.tsx b/packages/toc/src/toc_tree.tsx deleted file mode 100644 index 9dc31f12a7a9..000000000000 --- a/packages/toc/src/toc_tree.tsx +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import * as React from 'react'; -import { Widget } from '@lumino/widgets'; -import { IHeading } from './utils/headings'; -import { TableOfContentsRegistry as Registry } from './registry'; -import { TOCItem } from './toc_item'; -import { Signal } from '@lumino/signaling'; -import { TableOfContents } from './toc'; - -/** - * Interface describing component properties. - * - * @private - */ -interface IProperties extends React.Props { - /** - * Display title. - */ - title: string; - - /** - * List of headings to render. - */ - toc: IHeading[]; - - /** - * Toolbar. - */ - toolbar: any; - - entryClicked?: Signal; - - /** - * Table of contents generator. - */ - generator: Registry.IGenerator | null; - - /** - * Renders a heading item. - * - * @param item - heading - * @param toc - list of headings in toc to use for rendering current position - * @returns rendered heading - */ - itemRenderer: (item: IHeading, toc: IHeading[]) => JSX.Element | null; -} - -/** - * Interface describing component state. - * - * @private - */ -interface IState {} - -/** - * React component for a table of contents tree. - * - * @private - */ -class TOCTree extends React.Component { - /** - * Renders a table of contents tree. - */ - render() { - const Toolbar = this.props.toolbar; - - // Map the heading objects onto a list of JSX elements... - let i = 0; - let list: JSX.Element[] = this.props.toc.map(el => { - return ( - - ); - }); - return ( -
    -
    {this.props.title}
    - {Toolbar && } -
      {list}
    -
    - ); - } -} - -/** - * Exports. - */ -export { TOCTree }; diff --git a/packages/toc/src/tocitem.tsx b/packages/toc/src/tocitem.tsx new file mode 100644 index 000000000000..c069a4675613 --- /dev/null +++ b/packages/toc/src/tocitem.tsx @@ -0,0 +1,87 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { caretDownIcon, caretRightIcon } from '@jupyterlab/ui-components'; +import * as React from 'react'; +import { TableOfContents } from './tokens'; + +/** + * Interface describing component properties. + */ +export interface ITableOfContentsItemsProps { + /** + * Whether this item is active or not. + */ + isActive: boolean; + /** + * Heading to render. + */ + heading: TableOfContents.IHeading; + + /** + * On `mouse-down` event callback. + */ + onMouseDown: (heading: TableOfContents.IHeading) => void; + + /** + * Collapse event callback. + */ + onCollapse: (heading: TableOfContents.IHeading) => void; +} + +/** + * React component for a table of contents entry. + */ +export class TableOfContentsItem extends React.PureComponent< + React.PropsWithChildren +> { + /** + * Renders a table of contents entry. + * + * @returns rendered entry + */ + render(): JSX.Element | null { + const { children, isActive, heading, onCollapse, onMouseDown } = this.props; + + return ( +
  • +
    ) => { + // React only on deepest item + if (!event.defaultPrevented) { + event.preventDefault(); + onMouseDown(heading); + } + }} + > + + + {heading.prefix} + {heading.text} + +
    + {children && !heading.collapsed &&
      {children}
    } +
  • + ); + } +} diff --git a/packages/toc/src/toctree.tsx b/packages/toc/src/toctree.tsx new file mode 100644 index 000000000000..93abcb0b6110 --- /dev/null +++ b/packages/toc/src/toctree.tsx @@ -0,0 +1,102 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import * as React from 'react'; +import { TableOfContentsItem } from './tocitem'; +import { TableOfContents } from './tokens'; + +/** + * Interface describing component properties. + */ +export interface ITableOfContentsTreeProps { + /** + * Currently active heading. + */ + activeHeading: TableOfContents.IHeading | null; + /** + * Type of document supported by the model. + */ + documentType: string; + /** + * List of headings to render. + */ + headings: TableOfContents.IHeading[]; + /** + * Set active heading. + */ + setActiveHeading: (heading: TableOfContents.IHeading) => void; + /** + * Collapse heading callback. + */ + onCollapseChange: (heading: TableOfContents.IHeading) => void; +} + +/** + * React component for a table of contents tree. + */ +export class TableOfContentsTree extends React.PureComponent { + /** + * Renders a table of contents tree. + */ + render(): JSX.Element { + const { documentType } = this.props; + return ( +
      + {this.buildTree()} +
    + ); + } + + /** + * Convert the flat headings list to a nested tree list + */ + protected buildTree(): JSX.Element[] { + if (this.props.headings.length === 0) { + return []; + } + + const buildOneTree = (currentIndex: number): [JSX.Element, number] => { + const items = this.props.headings; + const children = new Array(); + const current = items[currentIndex]; + let nextCandidateIndex = currentIndex + 1; + + while (nextCandidateIndex < items.length) { + const candidateItem = items[nextCandidateIndex]; + if (candidateItem.level <= current.level) { + break; + } + const [child, nextIndex] = buildOneTree(nextCandidateIndex); + children.push(child); + nextCandidateIndex = nextIndex; + } + const currentTree = ( + + {children.length ? children : null} + + ); + return [currentTree, nextCandidateIndex]; + }; + + const trees = new Array(); + let currentIndex = 0; + while (currentIndex < this.props.headings.length) { + const [tree, nextIndex] = buildOneTree(currentIndex); + trees.push(tree); + currentIndex = nextIndex; + } + + return trees; + } +} diff --git a/packages/toc/src/tokens.ts b/packages/toc/src/tokens.ts new file mode 100644 index 000000000000..d6efca451e5c --- /dev/null +++ b/packages/toc/src/tokens.ts @@ -0,0 +1,302 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import type { ToolbarRegistry } from '@jupyterlab/apputils'; +import type { IObservableList } from '@jupyterlab/observables'; +import type { VDomRenderer } from '@jupyterlab/ui-components'; +import type { JSONObject } from '@lumino/coreutils'; +import { Token } from '@lumino/coreutils'; +import type { IDisposable } from '@lumino/disposable'; +import type { ISignal } from '@lumino/signaling'; +import type { Widget } from '@lumino/widgets'; + +/** + * Interface describing the table of contents registry. + */ +export interface ITableOfContentsRegistry { + /** + * Finds a table of contents model for a widget. + * + * ## Notes + * + * - If unable to find a table of contents model, the method return `undefined`. + * + * @param widget - widget + * @param configuration - Table of contents configuration + * @returns Table of contents model or undefined if not found + */ + getModel( + widget: Widget, + configuration?: TableOfContents.IConfig + ): TableOfContents.Model | undefined; + + /** + * Adds a table of contents factory to the registry. + * + * @param factory - table of contents factory + */ + add(factory: TableOfContents.IFactory): IDisposable; +} + +/** + * Table of contents registry token. + */ +export const ITableOfContentsRegistry = new Token( + '@jupyterlab/toc:ITableOfContentsRegistry', + 'A service to register table of content factory.' +); + +/** + * Interface for the table of contents tracker + */ +export interface ITableOfContentsTracker { + /** + * Get the model associated with a given widget. + * + * @param widget Widget + */ + get(widget: Widget): TableOfContents.IModel | null; +} + +/** + * Table of contents tracker token. + */ +export const ITableOfContentsTracker = new Token( + '@jupyterlab/toc:ITableOfContentsTracker', + 'A widget tracker for table of contents.' +); + +/** + * Namespace for table of contents interface + */ +export namespace TableOfContents { + /** + * Table of content model factory interface + */ + export interface IFactory< + W extends Widget = Widget, + H extends IHeading = IHeading + > { + /** + * Whether the factory can handle the widget or not. + * + * @param widget - widget + * @returns boolean indicating a ToC can be generated + */ + isApplicable: (widget: W) => boolean; + + /** + * Create a new table of contents model for the widget + * + * @param widget - widget + * @param configuration - Table of contents configuration + * @returns The table of contents model + */ + createNew: ( + widget: W, + configuration?: TableOfContents.IConfig + ) => IModel; + } + + /** + * Table of Contents configuration + * + * #### Notes + * A document model may ignore some of those options. + */ + export interface IConfig extends JSONObject { + /** + * Base level for the highest headings + */ + baseNumbering: number; + /** + * Maximal depth of headings to display + */ + maximalDepth: number; + /** + * Whether to number first-level headings or not. + */ + numberingH1: boolean; + /** + * Whether to number headings in document or not. + */ + numberHeaders: boolean; + /** + * Whether to include cell outputs in headings or not. + */ + includeOutput: boolean; + /** + * Whether to synchronize heading collapse state between the ToC and the document or not. + */ + syncCollapseState: boolean; + } + + /** + * Default table of content configuration + */ + export const defaultConfig: IConfig = { + baseNumbering: 1, + maximalDepth: 4, + numberingH1: true, + numberHeaders: false, + includeOutput: true, + syncCollapseState: false + }; + + /** + * Interface describing a heading. + */ + export interface IHeading { + /** + * Heading text. + */ + text: string; + + /** + * HTML heading level. + */ + level: number; + + /** + * Heading prefix. + */ + prefix?: string | null; + + /** + * Dataset to add to the item node + */ + dataset?: Record; + + /** + * Whether the heading is collapsed or not + */ + collapsed?: boolean; + + /** + * Whether the heading is marked to skip or not + */ + skip?: boolean; + } + + /** + * Interface describing a widget table of contents model. + */ + export interface IModel extends VDomRenderer.IModel { + /** + * Active heading + */ + readonly activeHeading: H | null; + + /** + * Signal emitted when the active heading changes. + */ + readonly activeHeadingChanged: ISignal, H | null>; + + /** + * Signal emitted when a table of content section collapse state changes. + * + * If all headings state are set at the same time, the argument is null. + */ + readonly collapseChanged: ISignal, H | null>; + + /** + * Model configuration + */ + readonly configuration: IConfig; + + /** + * Type of document supported by the model. + * + * #### Notes + * A `data-document-type` attribute with this value will be set + * on the tree view `.jp-TableOfContents-content[data-document-type="..."]` + */ + readonly documentType: string; + + /** + * Returns the list of headings. + * + * @returns list of headings + */ + readonly headings: H[]; + + /** + * Signal emitted when the headings changes. + */ + readonly headingsChanged: ISignal, void>; + + /** + * Whether the model needs to be kept up to date or not. + * + * ### Notes + * This is set to `true` if the ToC panel is visible and + * to `false` if it is hidden. But some models may require + * to be always active; e.g. to add numbering in the document. + */ + isActive: boolean; + + /** + * Set a new active heading. + * + * @param heading The new active heading + * @param emitSignal Whether to emit the activeHeadingChanged signal or not. + */ + setActiveHeading(heading: H | null, emitSignal?: boolean): void; + + /** + * Model configuration setter. + * + * @param c New configuration + */ + setConfiguration(c: Partial): void; + + /** + * List of configuration options supported by the model. + */ + readonly supportedOptions: (keyof IConfig)[]; + + /** + * Document title + */ + title?: string; + + /** + * Callback on heading collapse. + * + * @param options.heading The heading to change state (all headings if not provided) + * @param options.collapsed The new collapsed status (toggle existing status if not provided) + */ + toggleCollapse: (options: { heading?: H; collapsed?: boolean }) => void; + } + + /** + * Generic table of contents type + */ + export type Model = IModel; + + /** + * Interface describing table of contents widget options. + */ + export interface IOptions { + /** + * Table of contents model. + */ + model?: IModel; + + /** + * If no headings are present, a headline to display as a placeholder + */ + placeholderHeadline: string; + + /** + * If no headings are present, text to display as a placeholder + */ + placeholderText: string; + } + + /** + * Interface describing a toolbar item list + */ + export interface IToolbarItems + extends IObservableList {} +} diff --git a/packages/toc/src/tracker.ts b/packages/toc/src/tracker.ts new file mode 100644 index 000000000000..66539e59185a --- /dev/null +++ b/packages/toc/src/tracker.ts @@ -0,0 +1,41 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { Widget } from '@lumino/widgets'; +import { ITableOfContentsTracker, TableOfContents } from './tokens'; + +/** + * Table of contents tracker + */ +export class TableOfContentsTracker implements ITableOfContentsTracker { + /** + * Constructor + */ + constructor() { + this.modelMapping = new WeakMap(); + } + + /** + * Track a given model. + * + * @param widget Widget + * @param model Table of contents model + */ + add(widget: Widget, model: TableOfContents.Model): void { + this.modelMapping.set(widget, model); + } + + /** + * Get the table of contents model associated with a given widget. + * + * @param widget Widget + * @returns The table of contents model + */ + get(widget: Widget): TableOfContents.Model | null { + const model = this.modelMapping.get(widget); + + return !model || model.isDisposed ? null : model; + } + + protected modelMapping: WeakMap; +} diff --git a/packages/toc/src/treeview.tsx b/packages/toc/src/treeview.tsx new file mode 100644 index 000000000000..8ef477679d8d --- /dev/null +++ b/packages/toc/src/treeview.tsx @@ -0,0 +1,59 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { VDomRenderer } from '@jupyterlab/ui-components'; +import * as React from 'react'; +import { TableOfContentsTree } from './toctree'; +import { TableOfContents } from './tokens'; + +/** + * Table of contents widget. + */ +export class TableOfContentsWidget extends VDomRenderer | null> { + /** + * Constructor + * + * @param options Widget options + */ + constructor(options: TableOfContents.IOptions) { + super(options.model); + this._placeholderHeadline = options.placeholderHeadline; + this._placeholderText = options.placeholderText; + } + + /** + * Render the content of this widget using the virtual DOM. + * + * This method will be called anytime the widget needs to be rendered, which + * includes layout triggered rendering. + */ + render(): JSX.Element | null { + if (!this.model || this.model.headings.length === 0) { + return ( +
    +
    +

    {this._placeholderHeadline}

    +

    {this._placeholderText}

    +
    +
    + ); + } + + return ( + { + this.model!.toggleCollapse({ heading }); + }} + setActiveHeading={(heading: TableOfContents.IHeading) => { + this.model!.setActiveHeading(heading); + }} + > + ); + } + + readonly _placeholderHeadline: string; + readonly _placeholderText: string; +} diff --git a/packages/toc/src/utils/common.ts b/packages/toc/src/utils/common.ts new file mode 100644 index 000000000000..feeec1a050b7 --- /dev/null +++ b/packages/toc/src/utils/common.ts @@ -0,0 +1,220 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { TableOfContents } from '../tokens'; + +/** + * Class used to mark numbering prefix for headings in a document. + */ +export const NUMBERING_CLASS = 'numbering-entry'; + +/** + * HTML heading + */ +export interface IHTMLHeading extends TableOfContents.IHeading { + /** + * HTML id + */ + id?: string | null; +} + +/** + * Filter headings for table of contents and compute associated prefix + * + * @param headings Headings to process + * @param options Options + * @param initialLevels Initial levels for prefix computation + * @returns Extracted headings + */ +export function filterHeadings< + T extends TableOfContents.IHeading = TableOfContents.IHeading +>( + headings: T[], + options?: Partial, + initialLevels: number[] = [] +): T[] { + const config = { + ...TableOfContents.defaultConfig, + ...options + } as TableOfContents.IConfig; + + const levels = initialLevels; + let previousLevel = levels.length; + const filteredHeadings = new Array(); + for (const heading of headings) { + if (heading.skip) { + continue; + } + const level = heading.level; + + if (level > 0 && level <= config.maximalDepth) { + const prefix = getPrefix(level, previousLevel, levels, config); + previousLevel = level; + + filteredHeadings.push({ + ...heading, + prefix + }); + } + } + return filteredHeadings; +} + +/** + * Returns whether a MIME type corresponds to either HTML. + * + * @param mime - MIME type string + * @returns boolean indicating whether a provided MIME type corresponds to either HTML + * + * @example + * const bool = isHTML('text/html'); + * // returns true + * + * @example + * const bool = isHTML('text/plain'); + * // returns false + */ +export function isHTML(mime: string): boolean { + return mime === 'text/html'; +} + +/** + * Parse a HTML string for headings. + * + * ### Notes + * The html string is not sanitized - use with caution + * + * @param html HTML string to parse + * @param force Whether to ignore HTML headings with class jp-toc-ignore and tocSkip or not + * @returns Extracted headings + */ +export function getHTMLHeadings(html: string, force = true): IHTMLHeading[] { + const container: HTMLDivElement = document.createElement('div'); + container.innerHTML = html; + + const headings = new Array(); + const headers = container.querySelectorAll('h1, h2, h3, h4, h5, h6'); + for (const h of headers) { + const level = parseInt(h.tagName[1], 10); + + headings.push({ + text: h.textContent ?? '', + level, + id: h?.getAttribute('id'), + skip: + h.classList.contains('jp-toc-ignore') || h.classList.contains('tocSkip') + }); + } + return headings; +} + +/** + * Add an heading prefix to a HTML node. + * + * @param container HTML node containing the heading + * @param selector Heading selector + * @param prefix Title prefix to add + * @returns The modified HTML element + */ +export function addPrefix( + container: Element, + selector: string, + prefix: string +): Element | null { + let element = container.querySelector(selector) as Element | null; + + if (!element) { + return null; + } + + if (!element.querySelector(`span.${NUMBERING_CLASS}`)) { + addNumbering(element, prefix); + } else { + // There are likely multiple elements with the same selector + // => use the first one without prefix + const allElements = container.querySelectorAll(selector); + for (const el of allElements) { + if (!el.querySelector(`span.${NUMBERING_CLASS}`)) { + element = el; + addNumbering(el, prefix); + break; + } + } + } + + return element; +} + +/** + * Update the levels and create the numbering prefix + * + * @param level Current level + * @param previousLevel Previous level + * @param levels Levels list + * @param options Options + * @returns The numbering prefix + */ +export function getPrefix( + level: number, + previousLevel: number, + levels: number[], + options: TableOfContents.IConfig +): string { + const { baseNumbering, numberingH1, numberHeaders } = options; + let prefix = ''; + if (numberHeaders) { + const highestLevel = numberingH1 ? 1 : 2; + if (level > previousLevel) { + // Initialize the new levels + for (let l = previousLevel; l < level - 1; l++) { + levels[l] = 0; + } + levels[level - 1] = level === highestLevel ? baseNumbering : 1; + } else { + // Increment the current level + levels[level - 1] += 1; + + // Drop higher levels + if (level < previousLevel) { + levels.splice(level); + } + } + + // If the header list skips some level, replace missing elements by 0 + if (numberingH1) { + prefix = levels.map(level => level ?? 0).join('.') + '. '; + } else { + if (levels.length > 1) { + prefix = + levels + .slice(1) + .map(level => level ?? 0) + .join('.') + '. '; + } + } + } + return prefix; +} + +/** + * Add a numbering prefix to a HTML element. + * + * @param el HTML element + * @param numbering Numbering prefix to add + */ +function addNumbering(el: Element, numbering: string): void { + el.insertAdjacentHTML( + 'afterbegin', + `${numbering}` + ); +} + +/** + * Remove all numbering nodes from element + * @param element Node to clear + */ +export function clearNumbering(element: Element): void { + element?.querySelectorAll(`span.${NUMBERING_CLASS}`).forEach(el => { + el.remove(); + }); +} diff --git a/packages/toc/src/utils/generate_numbering.ts b/packages/toc/src/utils/generate_numbering.ts deleted file mode 100644 index 6eef9f2a17b5..000000000000 --- a/packages/toc/src/utils/generate_numbering.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { INumberingDictionary } from './numbering_dictionary'; - -// Maximum heading level: -const MAX_HEADING_LEVEL = 6; - -/** - * Updates numbering dictionary levels. - * - * ## Notes - * - * - Mutates a provided dictionary. - * - * @private - * @param dict - numbering dictionary - * @param level - current level - * @returns input dictionary - */ -function update(dict: any, level: number) { - for (let l = level + 1; l <= MAX_HEADING_LEVEL; l++) { - if (dict[l] !== void 0) { - dict[l] = void 0; - } - } - if (dict[level] === void 0) { - dict[level] = 1; - } else { - dict[level] += 1; - } - return dict; -} - -/** - * Generate the current numbering based on a provided numbering dictionary and the current level. - * - * @private - * @param dict - numbering dictionary - * @param level - current level - * @returns numbering - */ -function generateNumbering( - dict: INumberingDictionary, - level: number -): string | undefined { - if (dict === null) { - return; - } - let numbering = ''; - dict = update(dict, level); - if (level >= 1) { - for (let j = 1; j <= level; j++) { - numbering += (dict[j] === void 0 ? '0' : dict[j]) + '.'; - } - numbering += ' '; - } - return numbering; -} - -/** - * Exports. - */ -export { generateNumbering }; diff --git a/packages/toc/src/utils/headings.ts b/packages/toc/src/utils/headings.ts deleted file mode 100644 index c054c16d725a..000000000000 --- a/packages/toc/src/utils/headings.ts +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { Cell } from '@jupyterlab/cells'; - -/** - * Interface describing a heading. - */ -export interface IHeading { - /** - * Heading text. - */ - text: string; - - /** - * HTML heading level. - */ - level: number; - - /** - * Callback invoked upon clicking a ToC item. - * - * ## Notes - * - * - This will typically be used to scroll the parent widget to this item. - */ - onClick: () => void; - - /** - * Special HTML markup. - * - * ## Notes - * - * - The HTML string **should** be properly **sanitized**! - * - The HTML string can be used to render Markdown headings which have already been rendered as HTML. - */ - html?: string; -} - -/** - * Interface describing a numbered heading. - */ -export interface INumberedHeading extends IHeading { - /** - * Heading numbering. - */ - numbering?: string | null; -} - -/** - * Cell running status - */ -export enum RunningStatus { - /** - * Cell is idle - */ - Idle = -1, - /** - * Cell execution is scheduled - */ - Scheduled = 0, - /** - * Cell is running - */ - Running = 1 -} - -/** - * Interface describing a notebook cell heading. - */ -export interface INotebookHeading extends INumberedHeading { - /** - * Heading type. - */ - type: 'header' | 'markdown' | 'code'; - - /** - * Reference to a notebook cell. - */ - cellRef: Cell; - - /** - * Heading prompt. - */ - prompt?: string; - - /** - * Boolean indicating whether a heading has a child node. - */ - hasChild?: boolean; - - /** - * index of reference cell in the notebook - */ - index: number; - - /** - * Running status of the cells in the heading - */ - isRunning: RunningStatus; -} - -/** - * Tests whether a heading is a notebook heading. - * - * @param heading - heading to test - * @returns boolean indicating whether a heading is a notebook heading - */ - -export function isNotebookHeading(heading: any): boolean { - return heading.type !== undefined && heading.cellRef !== undefined; -} diff --git a/packages/toc/src/utils/index.ts b/packages/toc/src/utils/index.ts new file mode 100644 index 000000000000..3bb44e3a381f --- /dev/null +++ b/packages/toc/src/utils/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +export * from './common'; +export * as Markdown from './markdown'; diff --git a/packages/toc/src/utils/is_dom.ts b/packages/toc/src/utils/is_dom.ts deleted file mode 100644 index 434c712c3daa..000000000000 --- a/packages/toc/src/utils/is_dom.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -/** - * Returns whether a MIME type corresponds to either HTML or virtual DOM. - * - * @private - * @param mime - MIME type string - * @returns boolean indicating whether a provided MIME type corresponds to either HTML or virtual DOM - * - * @example - * const bool = isDOM('text/html'); - * // returns true - * - * @example - * const bool = isDOM('text/plain'); - * // returns false - */ -function isDOM(mime: string): boolean { - return mime === 'application/vdom.v1+json' || mime === 'text/html'; -} - -/** - * Exports. - */ -export { isDOM }; diff --git a/packages/toc/src/utils/is_markdown.ts b/packages/toc/src/utils/is_markdown.ts deleted file mode 100644 index 21f17849d6ed..000000000000 --- a/packages/toc/src/utils/is_markdown.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -/** - * Returns whether a MIME type corresponds to a Markdown flavor. - * - * @private - * @param mime - MIME type string - * @returns boolean indicating whether a provided MIME type corresponds to a Markdown flavor - * - * @example - * const bool = isMarkdown('text/markdown'); - * // returns true - * - * @example - * const bool = isMarkdown('text/plain'); - * // returns false - */ -function isMarkdown(mime: string): boolean { - return ( - mime === 'text/x-ipythongfm' || - mime === 'text/x-markdown' || - mime === 'text/x-gfm' || - mime === 'text/markdown' - ); -} - -/** - * Exports. - */ -export { isMarkdown }; diff --git a/packages/toc/src/utils/markdown.ts b/packages/toc/src/utils/markdown.ts new file mode 100644 index 000000000000..603d4473cf13 --- /dev/null +++ b/packages/toc/src/utils/markdown.ts @@ -0,0 +1,266 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { IMarkdownParser, renderMarkdown } from '@jupyterlab/rendermime'; +import { TableOfContents } from '../tokens'; + +/** + * Markdown heading + */ +export interface IMarkdownHeading extends TableOfContents.IHeading { + /** + * Heading line + */ + line: number; + + /** + * Raw string containing the heading + */ + raw: string; +} + +/** + * Build the heading html id. + * + * @param raw Raw markdown heading + * @param level Heading level + */ +export async function getHeadingId( + parser: IMarkdownParser, + raw: string, + level: number +): Promise { + try { + const innerHTML = await parser.render(raw); + + if (!innerHTML) { + return null; + } + + const container = document.createElement('div'); + container.innerHTML = innerHTML; + const header = container.querySelector(`h${level}`); + if (!header) { + return null; + } + + return renderMarkdown.createHeaderId(header); + } catch (reason) { + console.error('Failed to parse a heading.', reason); + } + + return null; +} + +/** + * Parses the provided string and returns a list of headings. + * + * @param text - Input text + * @returns List of headings + */ +export function getHeadings(text: string): IMarkdownHeading[] { + // Split the text into lines: + const lines = text.split('\n'); + + // Iterate over the lines to get the header level and text for each line: + const headings = new Array(); + let isCodeBlock; + let lineIdx = 0; + + // Don't check for Markdown headings if in a YAML frontmatter block. + // We can only start a frontmatter block on the first line of the file. + // At other positions in a markdown file, '---' represents a horizontal rule. + if (lines[lineIdx] === '---') { + // Search for another '---' and treat that as the end of the frontmatter. + // If we don't find one, treat the file as containing no frontmatter. + for ( + let frontmatterEndLineIdx = lineIdx + 1; + frontmatterEndLineIdx < lines.length; + frontmatterEndLineIdx++ + ) { + if (lines[frontmatterEndLineIdx] === '---') { + lineIdx = frontmatterEndLineIdx + 1; + break; + } + } + } + + for (; lineIdx < lines.length; lineIdx++) { + const line = lines[lineIdx]; + + if (line === '') { + // Bail early + continue; + } + + // Don't check for Markdown headings if in a code block + if (line.startsWith('```')) { + isCodeBlock = !isCodeBlock; + } + if (isCodeBlock) { + continue; + } + + const heading = parseHeading(line, lines[lineIdx + 1]); // append the next line to capture alternative style Markdown headings + + if (heading) { + headings.push({ + ...heading, + line: lineIdx + }); + } + } + return headings; +} + +const MARKDOWN_MIME_TYPE = [ + 'text/x-ipythongfm', + 'text/x-markdown', + 'text/x-gfm', + 'text/markdown' +]; + +/** + * Returns whether a MIME type corresponds to a Markdown flavor. + * + * @param mime - MIME type string + * @returns boolean indicating whether a provided MIME type corresponds to a Markdown flavor + * + * @example + * const bool = isMarkdown('text/markdown'); + * // returns true + * + * @example + * const bool = isMarkdown('text/plain'); + * // returns false + */ +export function isMarkdown(mime: string): boolean { + return MARKDOWN_MIME_TYPE.includes(mime); +} + +/** + * Interface describing a parsed heading result. + * + * @private + */ +interface IHeader { + /** + * Heading text. + */ + text: string; + + /** + * Heading level. + */ + level: number; + + /** + * Raw string containing the heading + */ + raw: string; + + /** + * Whether the heading is marked to skip or not + */ + skip: boolean; +} + +/** + * Parses a heading, if one exists, from a provided string. + * + * ## Notes + * + * - Heading examples: + * + * - Markdown heading: + * + * ``` + * # Foo + * ``` + * + * - Markdown heading (alternative style): + * + * ``` + * Foo + * === + * ``` + * + * ``` + * Foo + * --- + * ``` + * + * - HTML heading: + * + * ``` + *

    Foo

    + * ``` + * + * @private + * @param line - Line to parse + * @param nextLine - The line after the one to parse + * @returns heading info + * + * @example + * const out = parseHeading('### Foo\n'); + * // returns {'text': 'Foo', 'level': 3} + * + * @example + * const out = parseHeading('Foo\n===\n'); + * // returns {'text': 'Foo', 'level': 1} + * + * @example + * const out = parseHeading('

    Foo

    \n'); + * // returns {'text': 'Foo', 'level': 4} + * + * @example + * const out = parseHeading('Foo'); + * // returns null + */ +function parseHeading(line: string, nextLine?: string): IHeader | null { + // Case: Markdown heading + let match = line.match(/^([#]{1,6}) (.*)/); + if (match) { + return { + text: cleanTitle(match[2]), + level: match[1].length, + raw: line, + skip: skipHeading.test(match[0]) + }; + } + // Case: Markdown heading (alternative style) + if (nextLine) { + match = nextLine.match(/^ {0,3}([=]{2,}|[-]{2,})\s*$/); + if (match) { + return { + text: cleanTitle(line), + level: match[1][0] === '=' ? 1 : 2, + raw: [line, nextLine].join('\n'), + skip: skipHeading.test(line) + }; + } + } + // Case: HTML heading (WARNING: this is not particularly robust, as HTML headings can span multiple lines) + match = line.match(/(.*)<\/h\1>/i); + if (match) { + return { + text: match[2], + level: parseInt(match[1], 10), + skip: skipHeading.test(match[0]), + raw: line + }; + } + + return null; +} + +function cleanTitle(heading: string): string { + // take special care to parse Markdown links into raw text + return heading.replace(/\[(.+)\]\(.+\)/g, '$1'); +} + +/** + * Ignore title with html tag with a class name equal to `jp-toc-ignore` or `tocSkip` + */ +const skipHeading = + /<\w+\s(.*?\s)?class="(.*?\s)?(jp-toc-ignore|tocSkip)(\s.*?)?"(\s.*?)?>/; diff --git a/packages/toc/src/utils/numbering_dictionary.ts b/packages/toc/src/utils/numbering_dictionary.ts deleted file mode 100644 index 1cf65eb40b48..000000000000 --- a/packages/toc/src/utils/numbering_dictionary.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -/** - * Interface describing a numbering dictionary. - * - * @private - */ -interface INumberingDictionary { - /** - * Level numbering. - */ - [level: number]: number; -} - -/** - * Exports. - */ -export { INumberingDictionary }; diff --git a/packages/toc/src/utils/parse_heading.ts b/packages/toc/src/utils/parse_heading.ts deleted file mode 100644 index a4ee6a6e031a..000000000000 --- a/packages/toc/src/utils/parse_heading.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -/** - * Interface describing a parsed heading result. - * - * @private - */ -interface IHeading { - /** - * Heading text. - */ - text: string; - - /** - * Heading level. - */ - level: number; - - /** - * Heading type. - */ - type: 'html' | 'markdown' | 'markdown-alt'; -} - -/** - * Parses a heading, if one exists, from a provided string. - * - * ## Notes - * - * - Heading examples: - * - * - Markdown heading: - * - * ``` - * # Foo - * ``` - * - * - Markdown heading (alternative style): - * - * ``` - * Foo - * === - * ``` - * - * ``` - * Foo - * --- - * ``` - * - * - HTML heading: - * - * ``` - *

    Foo

    - * ``` - * - * @private - * @param str - input text - * @returns heading info - * - * @example - * const out = parseHeading('### Foo\n'); - * // returns {'text': 'Foo', 'level': 3, 'type': 'markdown'} - * - * @example - * const out = parseHeading('Foo\n===\n'); - * // returns {'text': 'Foo', 'level': 1, 'type': 'markdown-alt'} - * - * @example - * const out = parseHeading('

    Foo

    \n'); - * // returns {'text': 'Foo', 'level': 4, 'type': 'html'} - * - * @example - * const out = parseHeading('Foo'); - * // returns null - */ -function parseHeading(str: string): IHeading | null { - const lines = str.split('\n'); - - // Case: Markdown heading - let match = lines[0].match(/^([#]{1,6}) (.*)/); - if (match) { - return { - text: match[2].replace(/\[(.+)\]\(.+\)/g, '$1'), // take special care to parse Markdown links into raw text - level: match[1].length, - type: 'markdown' - }; - } - // Case: Markdown heading (alternative style) - if (lines.length > 1) { - match = lines[1].match(/^ {0,3}([=]{2,}|[-]{2,})\s*$/); - if (match) { - return { - text: lines[0].replace(/\[(.+)\]\(.+\)/g, '$1'), // take special care to parse Markdown links into raw text - level: match[1][0] === '=' ? 1 : 2, - type: 'markdown-alt' - }; - } - } - // Case: HTML heading (WARNING: this is not particularly robust, as HTML headings can span multiple lines) - match = lines[0].match(/(.*)<\/h\1>/i); - if (match) { - return { - text: match[2], - level: parseInt(match[1], 10), - type: 'html' - }; - } - return null; -} - -/** - * Exports. - */ -export { parseHeading }; diff --git a/packages/toc/src/utils/sanitizer_options.ts b/packages/toc/src/utils/sanitizer_options.ts deleted file mode 100644 index 68699892628e..000000000000 --- a/packages/toc/src/utils/sanitizer_options.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -/** - * Allowed HTML tags and associated attributes for ToC entries when sanitizing HTML headings. - * - * ## Notes - * - * - We specifically disallow anchor tags, since we are adding our own. - * - * @private - */ -const sanitizerOptions = { - allowedTags: [ - 'p', - 'blockquote', - 'b', - 'i', - 'strong', - 'em', - 'strike', - 'code', - 'br', - 'div', - 'span', - 'pre', - 'del' - ], - allowedAttributes: { - // Allow "class" attribute for tags. - code: ['class'], - // Allow "class" attribute for tags. - span: ['class'], - // Allow "class" attribute for
    tags. - div: ['class'], - // Allow "class" attribute for

    tags. - p: ['class'], - // Allow "class" attribute for

     tags.
    -    pre: ['class']
    -  }
    -};
    -
    -/**
    - * Exports.
    - */
    -export { sanitizerOptions };
    diff --git a/packages/toc/style/base.css b/packages/toc/style/base.css
    index c7149f1a8385..ec32191be179 100644
    --- a/packages/toc/style/base.css
    +++ b/packages/toc/style/base.css
    @@ -7,26 +7,8 @@
     | Table of Contents
     |----------------------------------------------------------------------------*/
     
    -.jp-TableOfContents-content {
    -  flex: 1 1 auto;
    -  margin: 0;
    -  padding: 0;
    -  list-style-type: none;
    -  overflow: auto;
    -  background-color: var(--jp-layout-color1);
    -}
    -
    -.jp-TableOfContents-content li {
    -  display: flex;
    -  flex-direction: row;
    -  padding: 4px 12px;
    -  -webkit-user-select: none;
    -  -moz-user-select: none;
    -  -ms-user-select: none;
    -  user-select: none;
    -  cursor: pointer;
    -  padding-top: 8px;
    -  padding-bottom: 8px;
    +:root {
    +  --jp-private-toc-active-width: 4px;
     }
     
     .jp-TableOfContents {
    @@ -38,405 +20,98 @@
       height: 100%;
     }
     
    -.jp-TableOfContents .jp-stack-panel-header {
    -  border-bottom: var(--jp-border-width) solid var(--jp-border-color2);
    -  flex: 0 0 auto;
    -  font-size: var(--jp-ui-font-size0);
    -  font-weight: 600;
    -  letter-spacing: 1px;
    -  margin: 0px;
    -  padding: 8px 12px;
    -  text-transform: uppercase;
    -}
    -
    -.jp-TableOfContents-codeContainer {
    -  overflow: hidden;
    -}
    -
    -.jp-TableOfContents-code {
    -  font-size: 9px;
    -  max-height: 70px;
    -}
    -
    -.cm-toc .CodeMirror {
    -  font-size: 9px;
    -  z-index: 0;
    -  border: var(--jp-border-width) solid var(--jp-cell-editor-border-color);
    -  border-radius: 0px;
    -  background: var(--jp-cell-editor-background);
    -  max-width: 100%;
    -  max-height: 36px;
    +.jp-TableOfContents-placeholder {
    +  text-align: center;
     }
     
    -.toc-code-span {
    -  width: 100%;
    -  max-width: 100%;
    -  overflow: hidden;
    +.jp-TableOfContents-placeholderContent {
    +  color: var(--jp-content-font-color2);
    +  padding: 8px;
     }
     
    -.cm-toc .CodeMirror-scroll {
    -  overflow: hidden !important;
    +.jp-TableOfContents-placeholderContent > h3 {
    +  margin-bottom: var(--jp-content-heading-margin-bottom);
     }
     
    -.CodeMirror-scroll::-webkit-scrollbar-track {
    -  background-color: transparent;
    +.jp-TableOfContents .jp-SidePanel-content {
    +  overflow-y: auto;
     }
     
    -.toc-toolbar-icon,
    -.toc-toolbar-icon-selected {
    -  float: left;
    -  padding: 0px;
    +.jp-TableOfContents-tree {
       margin: 4px;
    -  display: flex;
    -  justify-content: center;
    -  align-items: center;
    -  background-repeat: no-repeat;
    -  background-color: none;
    -  background-size: 100%;
    -  background-position: center;
    -  height: 24px;
    -  width: 24px;
    -  margin: 4px;
    -  border-radius: 2px;
     }
     
    -[data-jp-theme-light='true'] .toc-toolbar-icon:hover {
    -  background-color: var(--jp-input-background);
    -}
    -
    -[data-jp-theme-light='false'] .toc-toolbar-icon:hover {
    -  background-color: #3a3a3a;
    +.jp-TableOfContents ol {
    +  list-style-type: none;
     }
     
    -[data-jp-theme-light='true'] .toc-toolbar-icon-selected {
    -  background-color: var(--jp-layout-color2);
    +/* stylelint-disable-next-line selector-max-type */
    +.jp-TableOfContents li > ol {
    +  /* Align left border with triangle icon center */
    +  padding-left: 11px;
     }
     
    -[data-jp-theme-light='false'] .toc-toolbar-icon-selected {
    -  background-color: #565656;
    +.jp-TableOfContents-content {
    +  /* left margin for the active heading indicator */
    +  margin: 0 0 0 var(--jp-private-toc-active-width);
    +  padding: 0;
    +  background-color: var(--jp-layout-color1);
     }
     
    -.toc-code-cell-prompt {
    -  flex: 0 0 27px;
    -  color: var(--jp-cell-prompt-not-active-font-color);
    -  opacity: var(--jp-cell-prompt-not-active-opacity);
    -  font-family: var(--jp-cell-prompt-font-family);
    -  padding: var(--jp-code-padding);
    -  padding-right: 0px;
    -  padding-left: 0px;
    -  letter-spacing: var(--jp-cell-prompt-letter-spacing);
    -  line-height: var(--jp-code-line-height);
    -  font-size: 8px;
    -  border: var(--jp-border-width) solid transparent;
    -  text-align: left;
    -  white-space: nowrap;
    -  overflow: hidden;
    -  text-overflow: ellipsis;
    +.jp-tocItem {
       -webkit-user-select: none;
       -moz-user-select: none;
       -ms-user-select: none;
       user-select: none;
     }
     
    -.toc-toolbar {
    -  position: relative;
    -  width: 100%;
    -  margin: 0px;
    -  user-select: none;
    -  border-bottom: var(--jp-border-width) solid var(--jp-border-color2);
    -  height: 36px;
    -  display: flex;
    -  align-items: center;
    -}
    -
    -.toc-code-cell-div {
    -  display: inline-flex;
    -  width: 100%;
    -}
    -
    -.toc-entry-holder {
    -  width: 100%;
    +.jp-tocItem-heading {
       display: flex;
    -  flex-direction: row;
    -  padding: 0px;
    -  margin: 0px;
    -  overflow: visible;
    -}
    -
    -.toc-Collapser-child {
    -  display: block;
    -  width: 100%;
    -  box-sizing: border-box;
    -  position: absolute;
    -  top: 0px;
    -  bottom: 0px;
    -}
    -
    -.toc-entry-holder:hover .toc-Collapser-child {
    -  box-shadow: var(--jp-elevation-z2);
    -  background: var(--jp-brand-color1);
    -  opacity: var(--jp-cell-collapser-not-active-hover-opacity);
    -}
    -
    -.toc-active-cell .toc-Collapser-child {
    -  background: var(--jp-brand-color1);
    -}
    -
    -.toc-active-cell .toc-Collapser-child:hover {
    -  background: var(--jp-brand-color0);
    -  opacity: 1;
    -}
    -
    -.toc-active-cell:hover .toc-Collapser-child {
    -  background: var(--jp-brand-color0);
    -  opacity: 1;
    -}
    -
    -.toc-Collapser-child {
    -  background: transparent;
    -}
    -
    -.toc-Collapser-child:hover {
    -  box-shadow: var(--jp-elevation-z2);
    -  background: var(--jp-brand-color1);
    -  opacity: var(--jp-cell-collapser-not-active-hover-opacity);
    -}
    -
    -.toc-twist-placeholder {
    -  max-width: 10px;
    -  opacity: 0;
    -  overflow: hidden;
    -}
    -
    -.cm-toc-plain-span {
    -  width: 100%;
    -  white-space: pre-wrap;
    -  display: block;
    -}
    -
    -.cm-toc-plain-textarea {
    -  font-size: 9px;
    -  z-index: 0;
    -  border: var(--jp-border-width) solid var(--jp-cell-editor-border-color2);
    -  border-radius: 0px;
    -  background: var(--jp-cell-editor-background);
    -  width: calc(100% - 9px);
    -  overflow: hidden;
    -  max-height: 74px;
    -  resize: none;
    -  font-family: var(--jp-code-font-family);
    -  outline: none;
    -  user-select: none;
    -  white-space: pre;
    -  padding: var(--jp-code-padding);
    -}
    -
    -.cm-toc .CodeMirror-sizer {
    -  min-width: 0px !important;
    -  min-height: 0px !important;
    -  margin-bottom: 0px !important;
    -}
    -
    -.cm-toc .CodeMirror-line {
    -  white-space: pre-wrap;
       cursor: pointer;
     }
     
    -.cm-toc .CodeMirror-lines {
    -  cursor: pointer;
    -}
    -
    -.toc-tag-dropdown {
    -  display: flex;
    -  width: 100%;
    -}
    -
    -.toc-tag-dropdown-button {
    -  margin-left: auto;
    -}
    -
    -.toc-tags-container {
    -  padding: 4px;
    -  border-bottom: var(--jp-border-width) solid var(--jp-border-color2);
    -}
    -
    -.toc-clear-button {
    -  font-size: 12px;
    -  color: var(--jp-ui-font-color1);
    -  padding-left: 15px;
    -  user-select: none;
    -  float: right;
    -}
    -
    -.toc-clear-button:hover {
    -  font-size: 12px;
    -  color: var(--jp-ui-font-color2);
    -  padding-left: 15px;
    -  user-select: none;
    -}
    -
    -.toc-filter-button {
    -  background-color: var(--jp-layout-color1);
    -  border: solid 1px var(--jp-layout-color4);
    -  border-radius: 3px;
    -  width: fit-content;
    -  padding: 5px;
    -  padding-left: 6px;
    -  padding-right: 6px;
    -  margin-right: 17px;
    -  color: var(--jp-layout-color5);
    -  float: right;
    -  font-size: 12px;
    -  user-select: none;
    -  margin-bottom: 13px;
    -}
    -
    -.toc-filter-button:hover {
    -  background-color: var(--jp-layout-color4);
    -  border: solid 1px var(--jp-layout-color4);
    -  color: var(--jp-layout-color1);
    -}
    -
    -.toc-filter-button-na {
    -  background-color: var(--jp-layout-color1);
    -  border: solid 1px var(--jp-ui-font-color3);
    -  border-radius: 3px;
    -  width: fit-content;
    -  padding: 5px;
    -  padding-left: 6px;
    -  padding-right: 6px;
    -  margin-right: 17px;
    -  color: var(--jp-ui-font-color3);
    -  float: right;
    -  font-size: 12px;
    -  user-select: none;
    -  margin-bottom: 13px;
    -}
    -
    -.toc-no-tags-div {
    -  font-size: 12px;
    -  padding: 3px;
    -  padding-bottom: 6px;
    -  margin: auto;
    -  color: var(--jp-layout-color4);
    -}
    -
    -.toc-tags-container {
    -  width: 100%;
    -}
    -
    -.jp-TableOfContents-content code {
    -  font-size: inherit;
    -}
    -
    -.toc-cell-item {
    -  padding-left: 10px;
    -  font-size: var(--jp-ui-font-size1);
    -  /* Push ellipse button and execution indicator to right */
    -  margin-right: auto;
    -}
    -
    -/* styles for tags */
    -
    -.toc-tag-label {
    -  font-size: 11px;
    -  max-width: 100%;
    -  text-overflow: ellipsis;
    -  display: inline-block;
    -  overflow: hidden;
    -  box-sizing: border-box;
    -  padding-top: 0px;
    -  margin-top: -1px;
    -  margin-bottom: 0px;
    -  user-select: none;
    -}
    -
    -.toc-tag {
    -  box-sizing: border-box;
    -  height: 24px;
    -  border-radius: 20px;
    -  padding: 10px;
    -  padding-bottom: 4px;
    -  padding-top: 5px;
    -  margin: 3px;
    -  width: fit-content;
    -  max-width: calc(100% - 25px);
    -}
    -
    -.toc-selected-tag {
    -  color: white;
    -  background-color: #2196f3;
    -  outline: none;
    -}
    -
    -.toc-unselected-tag {
    +.jp-tocItem-heading:hover {
       background-color: var(--jp-layout-color2);
    -  outline: none;
     }
     
    -.toc-tag-holder {
    -  display: flex;
    -  flex-wrap: wrap;
    -  height: fit-content;
    -  padding-bottom: 6px;
    -  padding-right: 20px;
    -  padding-left: 9px;
    -  padding-top: 6px;
    -}
    -
    -.toc-Ellipses {
    -  box-sizing: border-box;
    -  height: 16px;
    -}
    -
    -.toc-Ellipses:hover {
    -  border: var(--jp-border-width) solid var(--jp-border-color1);
    -  box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.25);
    -  background-color: var(--jp-layout-color0);
    +.jp-tocItem-content {
    +  display: block;
    +  padding: 4px 0;
    +  white-space: nowrap;
    +  text-overflow: ellipsis;
    +  overflow-x: hidden;
     }
     
    -/*
    - * Execution indicator
    - */
    -.toc-entry-holder::after {
    -  content: '';
    -  /* Must be identical to form a circle */
    -  width: 12px;
    -  height: 12px;
    -  margin: 2px;
    +.jp-tocItem-collapser {
    +  height: 20px;
    +  margin: 2px 2px 0;
    +  padding: 0;
       background: none;
       border: none;
    -  flex: auto 0 0;
    -}
    -
    -.toc-entry-holder[data-running='0']::after {
    -  border-radius: 50%;
    -  border: var(--jp-border-width) solid var(--jp-inverse-layout-color3);
    -  background: none;
    +  cursor: pointer;
     }
     
    -.toc-entry-holder[data-running='1']::after {
    -  border-radius: 50%;
    -  border: var(--jp-border-width) solid var(--jp-inverse-layout-color3);
    -  background-color: var(--jp-inverse-layout-color3);
    +.jp-tocItem-collapser:hover {
    +  background-color: var(--jp-layout-color3);
     }
     
    -/* 
    - * Indentation levels
    - */
    -
    -.toc-level-size-2 {
    -  margin-left: 16px;
    -}
    +/* Active heading indicator */
     
    -.toc-level-size-3 {
    -  margin-left: 36px;
    +.jp-tocItem-heading::before {
    +  content: ' ';
    +  background: transparent;
    +  width: var(--jp-private-toc-active-width);
    +  height: 24px;
    +  position: absolute;
    +  left: 0;
    +  border-radius: var(--jp-border-radius);
     }
     
    -.toc-level-size-4 {
    -  margin-left: 56px;
    +.jp-tocItem-heading.jp-tocItem-active::before {
    +  background-color: var(--jp-brand-color1);
     }
     
    -.toc-level-size-5 {
    -  margin-left: 76px;
    +.jp-tocItem-heading:hover.jp-tocItem-active::before {
    +  background: var(--jp-brand-color0);
    +  opacity: 1;
     }
    diff --git a/packages/toc/style/index.css b/packages/toc/style/index.css
    index 93abbd756e91..d8149c93b747 100644
    --- a/packages/toc/style/index.css
    +++ b/packages/toc/style/index.css
    @@ -9,10 +9,4 @@
     @import url('~@jupyterlab/apputils/style/index.css');
     @import url('~@jupyterlab/rendermime/style/index.css');
     @import url('~@jupyterlab/docregistry/style/index.css');
    -@import url('~@jupyterlab/docmanager/style/index.css');
    -@import url('~@jupyterlab/cells/style/index.css');
    -@import url('~@jupyterlab/fileeditor/style/index.css');
    -@import url('~@jupyterlab/markdownviewer/style/index.css');
    -@import url('~@jupyterlab/notebook/style/index.css');
    -
     @import url('./base.css');
    diff --git a/packages/toc/style/index.js b/packages/toc/style/index.js
    index 921cc7e90ad1..89ea34cd4bac 100644
    --- a/packages/toc/style/index.js
    +++ b/packages/toc/style/index.js
    @@ -9,10 +9,5 @@ import '@jupyterlab/ui-components/style/index.js';
     import '@jupyterlab/apputils/style/index.js';
     import '@jupyterlab/rendermime/style/index.js';
     import '@jupyterlab/docregistry/style/index.js';
    -import '@jupyterlab/docmanager/style/index.js';
    -import '@jupyterlab/cells/style/index.js';
    -import '@jupyterlab/fileeditor/style/index.js';
    -import '@jupyterlab/markdownviewer/style/index.js';
    -import '@jupyterlab/notebook/style/index.js';
     
     import './base.css';
    diff --git a/packages/toc/test/markdown.spec.ts b/packages/toc/test/markdown.spec.ts
    new file mode 100644
    index 000000000000..af0592d948cd
    --- /dev/null
    +++ b/packages/toc/test/markdown.spec.ts
    @@ -0,0 +1,404 @@
    +// Copyright (c) Jupyter Development Team.
    +// Distributed under the terms of the Modified BSD License.
    +
    +import { TableOfContentsUtils } from '@jupyterlab/toc';
    +
    +describe('TableOfContentsUtils', () => {
    +  describe('Markdown', () => {
    +    describe('#getHeadings', () => {
    +      it.each<[string, TableOfContentsUtils.Markdown.IMarkdownHeading[]]>([
    +        [
    +          '# Title',
    +          [
    +            {
    +              text: 'Title',
    +              level: 1,
    +              line: 0,
    +              raw: '# Title',
    +              prefix: '1. ',
    +              skip: false
    +            }
    +          ]
    +        ],
    +        [
    +          '## Title',
    +          [
    +            {
    +              text: 'Title',
    +              level: 2,
    +              line: 0,
    +              raw: '## Title',
    +              prefix: '0.1. ',
    +              skip: false
    +            }
    +          ]
    +        ],
    +        [
    +          '### Title',
    +          [
    +            {
    +              text: 'Title',
    +              level: 3,
    +              line: 0,
    +              raw: '### Title',
    +              prefix: '0.0.1. ',
    +              skip: false
    +            }
    +          ]
    +        ],
    +        [
    +          '#### Title',
    +          [
    +            {
    +              text: 'Title',
    +              level: 4,
    +              line: 0,
    +              raw: '#### Title',
    +              prefix: '0.0.0.1. ',
    +              skip: false
    +            }
    +          ]
    +        ],
    +        [
    +          '##### Title',
    +          [
    +            {
    +              text: 'Title',
    +              level: 5,
    +              line: 0,
    +              raw: '##### Title',
    +              prefix: '0.0.0.0.1. ',
    +              skip: false
    +            }
    +          ]
    +        ],
    +        [
    +          '###### Title',
    +          [
    +            {
    +              text: 'Title',
    +              level: 6,
    +              line: 0,
    +              raw: '###### Title',
    +              prefix: '0.0.0.0.0.1. ',
    +              skip: false
    +            }
    +          ]
    +        ],
    +        [
    +          'Title\n==',
    +          [
    +            {
    +              text: 'Title',
    +              level: 1,
    +              line: 0,
    +              raw: 'Title\n==',
    +              prefix: '1. ',
    +              skip: false
    +            }
    +          ]
    +        ],
    +        [
    +          'Title\n--',
    +          [
    +            {
    +              text: 'Title',
    +              level: 2,
    +              line: 0,
    +              raw: 'Title\n--',
    +              prefix: '0.1. ',
    +              skip: false
    +            }
    +          ]
    +        ],
    +        [
    +          '

    Title

    ', + [ + { + text: 'Title', + level: 1, + line: 0, + raw: '

    Title

    ', + prefix: '1. ', + skip: false + } + ] + ], + [ + '

    Title

    ', + [ + { + text: 'Title', + level: 2, + line: 0, + raw: '

    Title

    ', + prefix: '0.1. ', + skip: false + } + ] + ], + [ + '

    Title

    ', + [ + { + text: 'Title', + level: 3, + line: 0, + raw: '

    Title

    ', + prefix: '0.0.1. ', + skip: false + } + ] + ], + [ + '

    Title

    ', + [ + { + text: 'Title', + level: 4, + line: 0, + raw: '

    Title

    ', + prefix: '0.0.0.1. ', + skip: false + } + ] + ], + [ + '
    Title
    ', + [ + { + text: 'Title', + level: 5, + line: 0, + raw: '
    Title
    ', + prefix: '0.0.0.0.1. ', + skip: false + } + ] + ], + [ + '
    Title
    ', + [ + { + text: 'Title', + level: 6, + line: 0, + raw: '
    Title
    ', + prefix: '0.0.0.0.0.1. ', + skip: false + } + ] + ], + ['\nTitle\n\n==', []], + ['\nTitle\n\n--', []], + ['```\n# Title\n```', []], + ['```\nTitle\n--\n```', []], + ['```\n

    Title

    \n```', []], + ['---\n

    Title

    \n---', []], + ['---\n# Title\n---', []], + [ + `--- +

    Ignored

    +--- +# Title`, + [ + { + text: 'Title', + level: 1, + line: 3, + raw: '# Title', + prefix: '1. ', + skip: false + } + ] + ], + [ + `--- +front: matter +--- + +# Header + +> this has whitespace _after_`, + [ + { + text: 'Header', + level: 1, + line: 4, + raw: '# Header', + prefix: '1. ', + skip: false + } + ] + ], + [ + `--- +front: matter +--- +# Header + +--- +# Header between horizontal rules +--- + +# Header after horizontal rules`, + [ + { + text: 'Header', + level: 1, + line: 3, + raw: '# Header', + prefix: '1. ', + skip: false + }, + { + text: 'Header between horizontal rules', + level: 1, + line: 6, + raw: '# Header between horizontal rules', + prefix: '2. ', + skip: false + }, + { + text: 'Header after horizontal rules', + level: 1, + line: 9, + raw: '# Header after horizontal rules', + prefix: '3. ', + skip: false + } + ] + ], + [ + `--- +# Header`, + [ + { + text: 'Header', + level: 1, + line: 1, + raw: '# Header', + prefix: '1. ', + skip: false + } + ] + ] + ])('should extract headings from %s', (src, headers) => { + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.Markdown.getHeadings(src), + { + maximalDepth: 6, + numberHeaders: true + } + ); + expect(headings).toHaveLength(headers.length); + + for (let i = 0; i < headers.length; i++) { + expect(headings[i]).toEqual(headers[i]); + } + }); + }); + + it.each<[string]>([ + ['### Title '], + ['### Title '], + ['Title \n=='], + ['Title \n=='], + ['Title \n--'], + ['Title \n--'], + ['

    Title

    '], + [''] + ])('should skip the heading from %s', src => { + const headings = TableOfContentsUtils.Markdown.getHeadings(src); + expect(headings).toHaveLength(1); + expect(headings[0].skip).toEqual(true); + }); + + it('should clean the title', () => { + const src = '## Title [with](https://jupyter.org "title") link'; + const headings = TableOfContentsUtils.Markdown.getHeadings(src); + expect(headings).toHaveLength(1); + expect(headings[0]).toEqual({ + level: 2, + text: 'Title with link', + line: 0, + raw: src, + skip: false + }); + }); + + it.each<[number]>([[1], [2], [3], [4], [5], [6]])( + 'should limit the level to %d', + maximalDepth => { + const src = `# h1 +## h2 +### h3 +#### h4 +##### h5 +###### h6`; + + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.Markdown.getHeadings(src), + { + maximalDepth + } + ); + expect(headings).toHaveLength(maximalDepth); + expect(headings[headings.length - 1].level).toEqual(maximalDepth); + } + ); + + it.each<[boolean]>([[true], [false]])( + `should have prefix or not`, + numberHeaders => { + const src = '### h3'; + + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.Markdown.getHeadings(src), + { + numberHeaders + } + ); + expect(headings).toHaveLength(1); + expect(headings[0].prefix).toEqual(numberHeaders ? '0.0.1. ' : ''); + } + ); + + it.each<[boolean]>([[true], [false]])( + `should number h1 or not`, + numberingH1 => { + const src = '# h1'; + + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.Markdown.getHeadings(src), + { + numberingH1, + numberHeaders: true + } + ); + expect(headings).toHaveLength(1); + expect(headings[0].prefix).toEqual(numberingH1 ? '1. ' : ''); + } + ); + + it.each<[boolean]>([[true], [false]])( + `should respect base number`, + numberingH1 => { + const src = `# h1 +## h2`; + + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.Markdown.getHeadings(src), + { + numberingH1, + numberHeaders: true, + baseNumbering: 3 + } + ); + expect(headings).toHaveLength(2); + expect(headings[0].prefix).toEqual(numberingH1 ? '3. ' : ''); + expect(headings[1].prefix).toEqual(numberingH1 ? '3.1. ' : '3. '); + } + ); + }); +}); diff --git a/packages/toc/test/toc.spec.ts b/packages/toc/test/toc.spec.ts deleted file mode 100644 index 83697d5ac3fa..000000000000 --- a/packages/toc/test/toc.spec.ts +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { WidgetTracker } from '@jupyterlab/apputils'; -import { - CodeMirrorEditorFactory, - CodeMirrorMimeTypeService -} from '@jupyterlab/codemirror'; -import { DocumentManager } from '@jupyterlab/docmanager'; -import { - DocumentRegistry, - DocumentWidget, - IDocumentWidget, - TextModelFactory -} from '@jupyterlab/docregistry'; -import { FileEditor, FileEditorFactory } from '@jupyterlab/fileeditor'; -import { - MarkdownDocument, - MarkdownViewerFactory -} from '@jupyterlab/markdownviewer'; -import { - NotebookModelFactory, - NotebookPanel, - NotebookTracker, - NotebookWidgetFactory -} from '@jupyterlab/notebook'; -import { RenderMimeRegistry } from '@jupyterlab/rendermime'; -import { ServiceManager } from '@jupyterlab/services'; -import { defaultRenderMime, Mock, NBTestUtils } from '@jupyterlab/testutils'; -import * as ToC from '@jupyterlab/toc'; -import { UUID } from '@lumino/coreutils'; - -let manager: DocumentManager; -let tocWidget: ToC.TableOfContents; -let registry: DocumentRegistry; -let services: ServiceManager.IManager; -let factory: TextModelFactory; - -beforeAll(async () => { - jest.setTimeout(20000); - const opener: DocumentManager.IWidgetOpener = { - open: widget => { - // no-op - } - }; - factory = new TextModelFactory(); - registry = new DocumentRegistry({ - textModelFactory: factory - }); - const contentFactory = NBTestUtils.createNotebookPanelFactory(); - const notebookFactory = new NotebookModelFactory({}); - registry.addModelFactory(notebookFactory); - registry.addWidgetFactory( - new NotebookWidgetFactory({ - modelName: 'notebook', - contentFactory, - fileTypes: ['notebook'], - rendermime: defaultRenderMime(), - mimeTypeService: NBTestUtils.mimeTypeService, - name: 'notebook' - }) - ); - registry.addWidgetFactory( - new FileEditorFactory({ - editorServices: { - factoryService: new CodeMirrorEditorFactory(), - mimeTypeService: new CodeMirrorMimeTypeService() - }, - factoryOptions: { - name: 'editor', - fileTypes: ['*'], - defaultFor: ['*'] - } - }) - ); - registry.addWidgetFactory( - new MarkdownViewerFactory({ - rendermime: defaultRenderMime(), - name: 'Markdown Preview', - primaryFileType: registry.getFileType('markdown'), - fileTypes: ['markdown'], - defaultRendered: [] - }) - ); - services = new Mock.ServiceManagerMock(); - manager = new DocumentManager({ - registry, - opener, - manager: services - }); -}); - -describe('@jupyterlab/toc', () => { - describe('TableOfContents', () => { - describe('#constructor', () => { - it('should construct a new ToC widget', () => { - tocWidget = new ToC.TableOfContents({ - docmanager: manager, - rendermime: new RenderMimeRegistry() - }); - expect(tocWidget).toBeInstanceOf(ToC.TableOfContents); - }); - }); - }); - - describe('TableOfContentsRegistry', () => { - let registry: ToC.TableOfContentsRegistry; - - beforeAll(() => { - registry = new ToC.TableOfContentsRegistry(); - }); - - describe('Notebook Generator: IGenerator', () => { - let notebookTracker: NotebookTracker; - let notebookGenerator: ToC.TableOfContentsRegistry.IGenerator; - let notebookWidget: NotebookPanel; - - it('should create a notebook generator', () => { - notebookTracker = new NotebookTracker({ - namespace: 'notebook' - }); - notebookGenerator = ToC.createNotebookGenerator( - notebookTracker, - tocWidget, - NBTestUtils.defaultRenderMime().sanitizer - ); - }); - - it('should add a notebook generator to the registry', () => { - registry.add(notebookGenerator); - }); - - it('should find the notebook generator', async () => { - const path = UUID.uuid4() + '.ipynb'; - const newNotebookWidget = manager.createNew(path, 'notebook'); - expect(newNotebookWidget).toBeInstanceOf(NotebookPanel); - notebookWidget = newNotebookWidget as NotebookPanel; - await notebookTracker.add(notebookWidget); - const foundNotebookGenerator = registry.find(notebookWidget); - expect(foundNotebookGenerator).toBeDefined(); - }); - - it('should change current', async () => { - tocWidget.current = { - widget: notebookWidget, - generator: notebookGenerator - }; - expect(tocWidget.current.widget).toBeInstanceOf(NotebookPanel); - }); - }); - - describe('Markdown Generator: IGenerator>', () => { - let markdownTracker: WidgetTracker>; - let markdownGenerator: ToC.TableOfContentsRegistry.IGenerator>; - let markdownWidget: IDocumentWidget; - - it('should create a markdown generator', () => { - markdownTracker = new WidgetTracker>({ - namespace: 'markdown' - }); - markdownGenerator = ToC.createMarkdownGenerator( - markdownTracker, - tocWidget, - NBTestUtils.defaultRenderMime().sanitizer - ); - }); - - it('should add a markdown generator to the registry', () => { - registry.add(markdownGenerator); - }); - - it('should find the markdown generator', async () => { - const path = UUID.uuid4() + '.md'; - const newMarkdownWidget = manager.createNew(path); - expect(newMarkdownWidget).toBeInstanceOf(DocumentWidget); - markdownWidget = newMarkdownWidget as IDocumentWidget; - await markdownTracker.add(markdownWidget); - const foundMarkdownGenerator = registry.find(markdownWidget); - expect(foundMarkdownGenerator).toBeDefined(); - }); - - it('should change current', async () => { - tocWidget.current = { - widget: markdownWidget, - generator: markdownGenerator - }; - expect(tocWidget.current.widget).toBeInstanceOf(DocumentWidget); - }); - }); - - describe('Rendered Markdown Generator: IGenerator', () => { - let markdownTracker: WidgetTracker; - let markdownGenerator: ToC.TableOfContentsRegistry.IGenerator; - let markdownWidget: MarkdownDocument; - - it('should create a markdown generator', () => { - markdownTracker = new WidgetTracker({ - namespace: 'markdownviewer-widget' - }); - markdownGenerator = ToC.createRenderedMarkdownGenerator( - markdownTracker, - tocWidget, - NBTestUtils.defaultRenderMime().sanitizer - ); - }); - - it('should add a markdown generator to the registry', () => { - registry.add(markdownGenerator); - }); - - it('should find the markdown generator', async () => { - const path = UUID.uuid4() + '.md'; - const newMarkdownWidget = manager.createNew(path, 'Markdown Preview'); - expect(newMarkdownWidget).toBeInstanceOf(MarkdownDocument); - markdownWidget = newMarkdownWidget as MarkdownDocument; - await markdownTracker.add(markdownWidget); - const foundMarkdownGenerator = registry.find(markdownWidget); - expect(foundMarkdownGenerator).toBeDefined(); - }); - - it('should change current', async () => { - tocWidget.current = { - widget: markdownWidget, - generator: markdownGenerator - }; - expect(tocWidget.current.widget).toBeInstanceOf(MarkdownDocument); - }); - }); - - describe('Latex Generator: IGenerator>', () => { - let latexTracker: WidgetTracker>; - let latexGenerator: ToC.TableOfContentsRegistry.IGenerator>; - let latexWidget: IDocumentWidget; - - it('should create a latex generator', () => { - latexTracker = new WidgetTracker>({ - namespace: 'latex' - }); - latexGenerator = ToC.createLatexGenerator(latexTracker); - }); - - it('should add a latex generator to the registry', () => { - registry.add(latexGenerator); - }); - - it('should find the latex generator', async () => { - const path = UUID.uuid4() + '.tex'; - const newLatexWidget = manager.createNew(path); - expect(newLatexWidget).toBeInstanceOf(DocumentWidget); - latexWidget = newLatexWidget as IDocumentWidget; - await latexTracker.add(latexWidget); - const foundLatexGenerator = registry.find(latexWidget); - expect(foundLatexGenerator).toBeDefined(); - }); - - it('should change current', async () => { - tocWidget.current = { - widget: latexWidget, - generator: latexGenerator - }; - expect(tocWidget.current.widget).toBeInstanceOf(DocumentWidget); - }); - }); - - describe('Python Generator: IGenerator>', () => { - let pythonTracker: WidgetTracker>; - let pythonGenerator: ToC.TableOfContentsRegistry.IGenerator>; - let pythonWidget: IDocumentWidget; - - it('should create a python generator', () => { - pythonTracker = new WidgetTracker>({ - namespace: 'python' - }); - pythonGenerator = ToC.createPythonGenerator(pythonTracker); - }); - - it('should add a python generator to the registry', () => { - registry.add(pythonGenerator); - }); - - it('should find the python generator', async () => { - const path = UUID.uuid4() + '.py'; - const newPythonWidget = manager.createNew(path); - expect(newPythonWidget).toBeInstanceOf(DocumentWidget); - pythonWidget = newPythonWidget as IDocumentWidget; - await pythonTracker.add(pythonWidget); - const foundPythonGenerator = registry.find(pythonWidget); - expect(foundPythonGenerator).toBeDefined(); - }); - - it('should change current', async () => { - tocWidget.current = { - widget: pythonWidget, - generator: pythonGenerator - }; - expect(tocWidget.current.widget).toBeInstanceOf(DocumentWidget); - }); - }); - }); -}); diff --git a/packages/toc/test/utils.spec.ts b/packages/toc/test/utils.spec.ts new file mode 100644 index 000000000000..5812736a8d72 --- /dev/null +++ b/packages/toc/test/utils.spec.ts @@ -0,0 +1,172 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { TableOfContentsUtils } from '@jupyterlab/toc'; + +describe('TableOfContentsUtils', () => { + describe('#getHTMLHeadings', () => { + it.each<[string, TableOfContentsUtils.IHTMLHeading[]]>([ + [ + '

    Title

    ', + [ + { + text: 'Title', + level: 1, + id: null, + prefix: '1. ', + skip: false + } + ] + ], + [ + '

    Title

    ', + [ + { + text: 'Title', + level: 2, + id: null, + prefix: '0.1. ', + skip: false + } + ] + ], + [ + '

    Title

    ', + [ + { + text: 'Title', + level: 3, + id: null, + prefix: '0.0.1. ', + skip: false + } + ] + ], + [ + '

    Title

    ', + [ + { + text: 'Title', + level: 4, + id: 'header-4-id', + prefix: '0.0.0.1. ', + skip: false + } + ] + ], + [ + '
    Title
    ', + [ + { + text: 'Title', + level: 5, + id: null, + prefix: '0.0.0.0.1. ', + skip: false + } + ] + ], + [ + '
    Title
    ', + [ + { + text: 'Title', + level: 6, + id: 'another-h6-id', + prefix: '0.0.0.0.0.1. ', + skip: false + } + ] + ], + ['', []], + ['

    Title

    ', []] + ])('should extract headings from %s', (src, headers) => { + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.getHTMLHeadings(src), + { + maximalDepth: 6, + numberHeaders: true + } + ); + expect(headings).toHaveLength(headers.length); + + for (let i = 0; i < headers.length; i++) { + expect(headings[i]).toEqual(headers[i]); + } + }); + + it.each<[number]>([[1], [2], [3], [4], [5], [6]])( + 'should limit the level to %d', + maximalDepth => { + const src = `

    Title

    +

    Title

    +

    Title

    +

    Title

    +
    Title
    +
    Title
    `; + + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.getHTMLHeadings(src), + { + maximalDepth + } + ); + expect(headings).toHaveLength(maximalDepth); + expect(headings[headings.length - 1].level).toEqual(maximalDepth); + } + ); + + it.each<[boolean]>([[true], [false]])( + `should have prefix or not`, + numberHeaders => { + const src = '

    Title

    '; + + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.getHTMLHeadings(src), + { + numberHeaders + } + ); + expect(headings).toHaveLength(1); + expect(headings[0].prefix).toEqual(numberHeaders ? '0.0.1. ' : ''); + } + ); + + it.each<[boolean]>([[true], [false]])( + `should number h1 or not`, + numberingH1 => { + const src = '

    Title

    '; + + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.getHTMLHeadings(src), + { + numberingH1, + numberHeaders: true + } + ); + expect(headings).toHaveLength(1); + expect(headings[0].prefix).toEqual(numberingH1 ? '1. ' : ''); + } + ); + + it.each<[boolean]>([[true], [false]])( + `should respect base number`, + numberingH1 => { + const src = `

    Title

    +

    Title

    `; + + const headings = TableOfContentsUtils.filterHeadings( + TableOfContentsUtils.getHTMLHeadings(src), + { + numberHeaders: true, + numberingH1, + baseNumbering: 3 + } + ); + expect(headings).toHaveLength(2); + expect(headings[0].prefix).toEqual(numberingH1 ? '3. ' : ''); + expect(headings[1].prefix).toEqual(numberingH1 ? '3.1. ' : '3. '); + } + ); + }); +}); diff --git a/packages/toc/toc.gif b/packages/toc/toc.gif deleted file mode 100644 index da8daf0efec9..000000000000 Binary files a/packages/toc/toc.gif and /dev/null differ diff --git a/packages/toc/tsconfig.json b/packages/toc/tsconfig.json index 4261447d99e3..d2a5e05732cc 100644 --- a/packages/toc/tsconfig.json +++ b/packages/toc/tsconfig.json @@ -9,33 +9,18 @@ { "path": "../apputils" }, - { - "path": "../cells" - }, { "path": "../coreutils" }, - { - "path": "../docmanager" - }, { "path": "../docregistry" }, { - "path": "../fileeditor" - }, - { - "path": "../markdownviewer" - }, - { - "path": "../notebook" + "path": "../observables" }, { "path": "../rendermime" }, - { - "path": "../settingregistry" - }, { "path": "../translation" }, diff --git a/packages/toc/tsconfig.test.json b/packages/toc/tsconfig.test.json index 21da05da6895..c74d05d1b8e3 100644 --- a/packages/toc/tsconfig.test.json +++ b/packages/toc/tsconfig.test.json @@ -1,6 +1,6 @@ { "extends": "../../tsconfigbase.test", - "include": ["src/*", "test/*"], + "include": ["src/**/*", "test/*"], "compilerOptions": { "lib": ["DOM", "DOM.Iterable"] }, @@ -8,33 +8,18 @@ { "path": "../apputils" }, - { - "path": "../cells" - }, { "path": "../coreutils" }, - { - "path": "../docmanager" - }, { "path": "../docregistry" }, { - "path": "../fileeditor" - }, - { - "path": "../markdownviewer" - }, - { - "path": "../notebook" + "path": "../observables" }, { "path": "../rendermime" }, - { - "path": "../settingregistry" - }, { "path": "../translation" }, @@ -45,43 +30,7 @@ "path": "." }, { - "path": "../../testutils" - }, - { - "path": "../apputils" - }, - { - "path": "../cells" - }, - { - "path": "../coreutils" - }, - { - "path": "../docmanager" - }, - { - "path": "../docregistry" - }, - { - "path": "../fileeditor" - }, - { - "path": "../markdownviewer" - }, - { - "path": "../notebook" - }, - { - "path": "../rendermime" - }, - { - "path": "../settingregistry" - }, - { - "path": "../translation" - }, - { - "path": "../ui-components" + "path": "../testing" } ] } diff --git a/packages/tooltip-extension/package.json b/packages/tooltip-extension/package.json index 9d0a21547bc4..d4ae8780d7a8 100644 --- a/packages/tooltip-extension/package.json +++ b/packages/tooltip-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/tooltip-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Tooltip Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -28,7 +28,8 @@ "lib/*.js", "schema/*.json", "style/**/*.css", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -37,23 +38,24 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/codeeditor": "^3.6.6", - "@jupyterlab/console": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/fileeditor": "^3.6.6", - "@jupyterlab/notebook": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/tooltip": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/widgets": "^1.37.2" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/codeeditor": "^4.0.8", + "@jupyterlab/console": "^4.0.8", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/fileeditor": "^4.0.8", + "@jupyterlab/notebook": "^4.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/tooltip": "^4.0.8", + "@jupyterlab/translation": "^4.0.8", + "@lumino/algorithm": "^2.0.1", + "@lumino/coreutils": "^2.1.2", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/tooltip-extension/src/index.ts b/packages/tooltip-extension/src/index.ts index 367990483b5b..613aed9419b1 100644 --- a/packages/tooltip-extension/src/index.ts +++ b/packages/tooltip-extension/src/index.ts @@ -17,7 +17,8 @@ import { INotebookTracker } from '@jupyterlab/notebook'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { Kernel, KernelMessage, Session } from '@jupyterlab/services'; import { ITooltipManager, Tooltip } from '@jupyterlab/tooltip'; -import { find, toArray } from '@lumino/algorithm'; +import { ITranslator, nullTranslator } from '@jupyterlab/translation'; +import { find } from '@lumino/algorithm'; import { JSONObject } from '@lumino/coreutils'; import { Widget } from '@lumino/widgets'; @@ -39,13 +40,20 @@ namespace CommandIDs { */ const manager: JupyterFrontEndPlugin = { id: '@jupyterlab/tooltip-extension:manager', + description: 'Provides the tooltip manager.', autoStart: true, + optional: [ITranslator], provides: ITooltipManager, - activate: (app: JupyterFrontEnd): ITooltipManager => { + activate: ( + app: JupyterFrontEnd, + translator: ITranslator | null + ): ITooltipManager => { + const trans = (translator ?? nullTranslator).load('jupyterlab'); let tooltip: Tooltip | null = null; // Add tooltip dismiss command. app.commands.addCommand(CommandIDs.dismiss, { + label: trans.__('Dismiss the tooltip'), execute: () => { if (tooltip) { tooltip.dispose(); @@ -81,16 +89,23 @@ const manager: JupyterFrontEndPlugin = { * The console tooltip plugin. */ const consoles: JupyterFrontEndPlugin = { + // FIXME This should be in @jupyterlab/console-extension id: '@jupyterlab/tooltip-extension:consoles', + description: 'Adds the tooltip capability to consoles.', autoStart: true, + optional: [ITranslator], requires: [ITooltipManager, IConsoleTracker], activate: ( app: JupyterFrontEnd, manager: ITooltipManager, - consoles: IConsoleTracker + consoles: IConsoleTracker, + translator: ITranslator | null ): void => { + const trans = (translator ?? nullTranslator).load('jupyterlab'); + // Add tooltip launch command. app.commands.addCommand(CommandIDs.launchConsole, { + label: trans.__('Open the tooltip'), execute: () => { const parent = consoles.currentWidget; @@ -116,16 +131,23 @@ const consoles: JupyterFrontEndPlugin = { * The notebook tooltip plugin. */ const notebooks: JupyterFrontEndPlugin = { + // FIXME This should be in @jupyterlab/notebook-extension id: '@jupyterlab/tooltip-extension:notebooks', + description: 'Adds the tooltip capability to notebooks.', autoStart: true, + optional: [ITranslator], requires: [ITooltipManager, INotebookTracker], activate: ( app: JupyterFrontEnd, manager: ITooltipManager, - notebooks: INotebookTracker + notebooks: INotebookTracker, + translator: ITranslator | null ): void => { + const trans = (translator ?? nullTranslator).load('jupyterlab'); + // Add tooltip launch command. app.commands.addCommand(CommandIDs.launchNotebook, { + label: trans.__('Open the tooltip'), execute: () => { const parent = notebooks.currentWidget; @@ -151,15 +173,21 @@ const notebooks: JupyterFrontEndPlugin = { * The file editor tooltip plugin. */ const files: JupyterFrontEndPlugin = { + // FIXME This should be in @jupyterlab/fileeditor-extension id: '@jupyterlab/tooltip-extension:files', + description: 'Adds the tooltip capability to file editors.', autoStart: true, + optional: [ITranslator], requires: [ITooltipManager, IEditorTracker, IRenderMimeRegistry], activate: ( app: JupyterFrontEnd, manager: ITooltipManager, editorTracker: IEditorTracker, - rendermime: IRenderMimeRegistry + rendermime: IRenderMimeRegistry, + translator: ITranslator | null ): void => { + const trans = (translator ?? nullTranslator).load('jupyterlab'); + // Keep a list of active ISessions so that we can // clean them up when they are no longer needed. const activeSessions: { @@ -172,7 +200,7 @@ const files: JupyterFrontEndPlugin = { // matching path for the file editors. const onRunningChanged = ( sender: Session.IManager, - models: Session.IModel[] + models: Iterable ) => { editorTracker.forEach(file => { const model = find(models, m => file.context.path === m.path); @@ -200,7 +228,7 @@ const files: JupyterFrontEndPlugin = { } }); }; - onRunningChanged(sessions, toArray(sessions.running())); + onRunningChanged(sessions, sessions.running()); sessions.runningChanged.connect(onRunningChanged); // Clean up after a widget when it is disposed @@ -216,6 +244,7 @@ const files: JupyterFrontEndPlugin = { // Add tooltip launch command. app.commands.addCommand(CommandIDs.launchFile, { + label: trans.__('Open the tooltip'), execute: async () => { const parent = editorTracker.currentWidget; const kernel = @@ -283,7 +312,7 @@ namespace Private { */ export function fetch(options: IFetchOptions): Promise { const { detail, editor, kernel } = options; - const code = editor.model.value.text; + const code = editor.model.sharedModel.getSource(); const position = editor.getCursorPosition(); const offset = Text.jsIndexToCharIndex(editor.getOffsetAt(position), code); diff --git a/packages/tooltip-extension/tsconfig.json b/packages/tooltip-extension/tsconfig.json index c5b3c08fa754..5964fb6c53f2 100644 --- a/packages/tooltip-extension/tsconfig.json +++ b/packages/tooltip-extension/tsconfig.json @@ -32,6 +32,9 @@ }, { "path": "../tooltip" + }, + { + "path": "../translation" } ] } diff --git a/packages/tooltip/package.json b/packages/tooltip/package.json index 15337f5b7f9d..19ff148df647 100644 --- a/packages/tooltip/package.json +++ b/packages/tooltip/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/tooltip", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Tooltip Widget", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -27,7 +27,8 @@ "lib/*.js.map", "lib/*.js", "style/*.css", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -36,18 +37,18 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/codeeditor": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@lumino/coreutils": "^1.11.0", - "@lumino/messaging": "^1.10.0", - "@lumino/widgets": "^1.37.2" + "@jupyterlab/codeeditor": "^4.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/ui-components": "^4.0.8", + "@lumino/coreutils": "^2.1.2", + "@lumino/messaging": "^2.0.1", + "@lumino/widgets": "^2.3.0" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/tooltip/src/tokens.ts b/packages/tooltip/src/tokens.ts index da0f5d8affe1..6b43aef56449 100644 --- a/packages/tooltip/src/tokens.ts +++ b/packages/tooltip/src/tokens.ts @@ -7,14 +7,13 @@ import { Kernel } from '@jupyterlab/services'; import { Token } from '@lumino/coreutils'; import { Widget } from '@lumino/widgets'; -/* tslint:disable */ /** * The tooltip manager token. */ export const ITooltipManager = new Token( - '@jupyterlab/tooltip:ITooltipManager' + '@jupyterlab/tooltip:ITooltipManager', + 'A service for the tooltip manager for the application. Use this to allow your extension to invoke a tooltip.' ); -/* tslint:enable */ /** * A manager to register tooltips with parent widgets. @@ -27,7 +26,7 @@ export interface ITooltipManager { } /** - * A namespace for `ICompletionManager` interface specifications. + * A namespace for `ITooltipManager` interface specifications. */ export namespace ITooltipManager { /** diff --git a/packages/tooltip/src/widget.ts b/packages/tooltip/src/widget.ts index afe4318d9875..1dcdaf7e5f0e 100644 --- a/packages/tooltip/src/widget.ts +++ b/packages/tooltip/src/widget.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { HoverBox } from '@jupyterlab/apputils'; +import { HoverBox } from '@jupyterlab/ui-components'; import { CodeEditor } from '@jupyterlab/codeeditor'; import { IRenderMime, @@ -219,7 +219,7 @@ export class Tooltip extends Widget { const editor = this._editor; - const anchor = editor.getCoordinateForPosition(position) as ClientRect; + const anchor = editor.getCoordinateForPosition(position); const style = window.getComputedStyle(this.node); const paddingLeft = parseInt(style.paddingLeft!, 10) || 0; diff --git a/packages/tooltip/style/index.css b/packages/tooltip/style/index.css index eb7f17bbda79..2746b5712717 100644 --- a/packages/tooltip/style/index.css +++ b/packages/tooltip/style/index.css @@ -5,8 +5,7 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ @import url('~@lumino/widgets/style/index.css'); -@import url('~@jupyterlab/apputils/style/index.css'); +@import url('~@jupyterlab/ui-components/style/index.css'); @import url('~@jupyterlab/codeeditor/style/index.css'); @import url('~@jupyterlab/rendermime/style/index.css'); - @import url('./base.css'); diff --git a/packages/tooltip/style/index.js b/packages/tooltip/style/index.js index 59d2c52c6228..cb61b711ac26 100644 --- a/packages/tooltip/style/index.js +++ b/packages/tooltip/style/index.js @@ -5,7 +5,7 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ import '@lumino/widgets/style/index.js'; -import '@jupyterlab/apputils/style/index.js'; +import '@jupyterlab/ui-components/style/index.js'; import '@jupyterlab/codeeditor/style/index.js'; import '@jupyterlab/rendermime/style/index.js'; diff --git a/packages/tooltip/tsconfig.json b/packages/tooltip/tsconfig.json index e0912df727b3..7ac0946e9513 100644 --- a/packages/tooltip/tsconfig.json +++ b/packages/tooltip/tsconfig.json @@ -6,9 +6,6 @@ }, "include": ["src/*"], "references": [ - { - "path": "../apputils" - }, { "path": "../codeeditor" }, @@ -17,6 +14,9 @@ }, { "path": "../services" + }, + { + "path": "../ui-components" } ] } diff --git a/packages/translation-extension/package.json b/packages/translation-extension/package.json index bbfaece32b6b..899ecb74289c 100644 --- a/packages/translation-extension/package.json +++ b/packages/translation-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/translation-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Translation services", "keywords": [ "jupyter", @@ -28,7 +28,8 @@ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "schema/**/*.{json,}", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc", @@ -38,15 +39,15 @@ "watch": "tsc -w" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/mainmenu": "^3.6.6", - "@jupyterlab/settingregistry": "^3.6.6", - "@jupyterlab/translation": "^3.6.6" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/mainmenu": "^4.0.8", + "@jupyterlab/settingregistry": "^4.0.8", + "@jupyterlab/translation": "^4.0.8" }, "devDependencies": { "rimraf": "~3.0.0", - "typescript": "~4.1.3" + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/translation-extension/src/index.ts b/packages/translation-extension/src/index.ts index b0b9120ca1ed..f47bbfab5cfd 100644 --- a/packages/translation-extension/src/index.ts +++ b/packages/translation-extension/src/index.ts @@ -8,10 +8,11 @@ */ import { + ILabShell, JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; -import { Dialog, showDialog } from '@jupyterlab/apputils'; +import { Dialog, ICommandPalette, showDialog } from '@jupyterlab/apputils'; import { IMainMenu } from '@jupyterlab/mainmenu'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { @@ -20,14 +21,6 @@ import { TranslationManager } from '@jupyterlab/translation'; -/** - * A namespace for command IDs. - */ -export namespace CommandIDs { - export const installAdditionalLanguages = - 'jupyterlab-translation:install-additional-languages'; -} - /** * Translation plugins */ @@ -35,13 +28,16 @@ const PLUGIN_ID = '@jupyterlab/translation-extension:plugin'; const translator: JupyterFrontEndPlugin = { id: '@jupyterlab/translation:translator', + description: 'Provides the application translation object.', autoStart: true, requires: [JupyterFrontEnd.IPaths, ISettingRegistry], + optional: [ILabShell], provides: ITranslator, activate: async ( app: JupyterFrontEnd, paths: JupyterFrontEnd.IPaths, - settings: ISettingRegistry + settings: ISettingRegistry, + labShell: ILabShell | null ) => { const setting = await settings.load(PLUGIN_ID); const currentLocale: string = setting.get('locale').composite as string; @@ -57,6 +53,14 @@ const translator: JupyterFrontEndPlugin = { serverSettings ); await translationManager.fetch(currentLocale); + + // Set translator to UI + if (labShell) { + labShell.translator = translationManager; + } + + Dialog.translator = translationManager; + return translationManager; } }; @@ -66,13 +70,16 @@ const translator: JupyterFrontEndPlugin = { */ const langMenu: JupyterFrontEndPlugin = { id: PLUGIN_ID, - requires: [IMainMenu, ISettingRegistry, ITranslator], + description: 'Adds translation commands and settings.', + requires: [ISettingRegistry, ITranslator], + optional: [IMainMenu, ICommandPalette], autoStart: true, activate: ( app: JupyterFrontEnd, - mainMenu: IMainMenu, settings: ISettingRegistry, - translator: ITranslator + translator: ITranslator, + mainMenu: IMainMenu | null, + palette: ICommandPalette | null ) => { const trans = translator.load('jupyterlab'); const { commands } = app; @@ -92,17 +99,28 @@ const langMenu: JupyterFrontEndPlugin = { .then(setting => { // Read the settings loadSetting(setting); - document.documentElement.lang = currentLocale; + + // Ensure currentLocale is not 'default' which is not a valid language code + if (currentLocale !== 'default') { + document.documentElement.lang = (currentLocale ?? '').replace( + '_', + '-' + ); + } else { + document.documentElement.lang = 'en-US'; + } // Listen for your plugin setting changes using Signal setting.changed.connect(loadSetting); // Create a languages menu - const languagesMenu = mainMenu.settingsMenu.items.find( - item => - item.type === 'submenu' && - item.submenu?.id === 'jp-mainmenu-settings-language' - )?.submenu; + const languagesMenu = mainMenu + ? mainMenu.settingsMenu.items.find( + item => + item.type === 'submenu' && + item.submenu?.id === 'jp-mainmenu-settings-language' + )?.submenu + : null; let command: string; @@ -160,6 +178,13 @@ const langMenu: JupyterFrontEndPlugin = { args: {} }); } + + if (palette) { + palette.addItem({ + category: trans.__('Display Languages'), + command + }); + } } }) .catch(reason => { diff --git a/packages/translation/babel.config.js b/packages/translation/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/packages/translation/babel.config.js +++ b/packages/translation/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/packages/translation/jest.config.js b/packages/translation/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/translation/jest.config.js +++ b/packages/translation/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/translation/package.json b/packages/translation/package.json index c09cc79de2ea..3f4beabdf831 100644 --- a/packages/translation/package.json +++ b/packages/translation/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/translation", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Translation services", "keywords": [ "jupyter", @@ -23,7 +23,8 @@ "lib": "lib/" }, "files": [ - "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}" + "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc", @@ -34,22 +35,23 @@ "eslint:check": "eslint . --ext .ts,.tsx", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -w" }, "dependencies": { - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/services": "^6.6.6", - "@jupyterlab/statedb": "^3.6.6", - "@lumino/coreutils": "^1.11.0" + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/rendermime-interfaces": "^3.8.8", + "@jupyterlab/services": "^7.0.8", + "@jupyterlab/statedb": "^4.0.8", + "@lumino/coreutils": "^2.1.2" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "typescript": "~4.1.3" + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/translation/src/base.ts b/packages/translation/src/base.ts index d0e22287ec55..2645d928f576 100644 --- a/packages/translation/src/base.ts +++ b/packages/translation/src/base.ts @@ -13,14 +13,12 @@ class NullTranslator implements ITranslator { this._languageBundle = bundle; } + readonly languageCode: string = 'en'; + load(domain: string): TranslationBundle { return this._languageBundle; } - locale(): string { - return 'en'; - } - private _languageBundle: TranslationBundle; } diff --git a/packages/translation/src/gettext.ts b/packages/translation/src/gettext.ts index 2afda6b4ca88..cbdb0b7f0570 100644 --- a/packages/translation/src/gettext.ts +++ b/packages/translation/src/gettext.ts @@ -181,7 +181,7 @@ class Gettext { /** * Get current context delimiter. * - * @return The current delimiter. + * @returns The current delimiter. */ getContextDelimiter(): string { return this._contextDelimiter; @@ -199,7 +199,7 @@ class Gettext { /** * Get current locale. * - * @return The current locale. + * @returns The current locale. */ getLocale(): string { return this._locale; @@ -217,7 +217,7 @@ class Gettext { /** * Get current domain. * - * @return The current domain string. + * @returns The current domain string. */ getDomain(): string { return this._domain; @@ -235,7 +235,7 @@ class Gettext { /** * Get current strings prefix. * - * @return The strings prefix. + * @returns The strings prefix. */ getStringsPrefix(): string { return this._stringsPrefix; @@ -303,7 +303,7 @@ class Gettext { * @param msgid - The singular string to translate. * @param args - Any additional values to use with interpolation. * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. * * ### Notes * This is not a private method (starts with an underscore) it is just @@ -321,7 +321,7 @@ class Gettext { * @param n - The number for pluralization. * @param args - Any additional values to use with interpolation. * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. * * ### Notes * This is not a private method (starts with an underscore) it is just @@ -338,7 +338,7 @@ class Gettext { * @param msgid - The singular string to translate. * @param args - Any additional values to use with interpolation. * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. * * ### Notes * This is not a private method (starts with an underscore) it is just @@ -357,7 +357,7 @@ class Gettext { * @param n - The number for pluralization. * @param args - Any additional values to use with interpolation. * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. * * ### Notes * This is not a private method (starts with an underscore) it is just @@ -379,7 +379,7 @@ class Gettext { * @param msgid - The singular string to translate. * @param args - Any additional values to use with interpolation. * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. */ gettext(msgid: string, ...args: any[]): string { return this.dcnpgettext('', '', msgid, '', 0, ...args); @@ -391,7 +391,7 @@ class Gettext { * @param msgid - The singular string to translate. * @param args - Any additional values to use with interpolation. * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. */ ngettext( msgid: string, @@ -409,7 +409,7 @@ class Gettext { * @param msgid - The singular string to translate. * @param args - Any additional values to use with interpolation. * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. * * ### Notes * This is not a private method (starts with an underscore) it is just @@ -428,7 +428,7 @@ class Gettext { * @param n - The number for pluralization. * @param args - Any additional values to use with interpolation * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. */ npgettext( msgctxt: string, @@ -450,7 +450,7 @@ class Gettext { * @param n - The number for pluralization. * @param args - Any additional values to use with interpolation * - * @return A translated string if found, or the original string. + * @returns A translated string if found, or the original string. */ dcnpgettext( domain: string, @@ -518,7 +518,7 @@ class Gettext { * * @param locale - The locale string. * - * @return An array of locales. + * @returns An array of locales. */ private expandLocale(locale: string): Array { let locales: Array = [locale]; @@ -535,8 +535,9 @@ class Gettext { * Split a locale into parent locales. "es-CO" -> ["es-CO", "es"] * * @param pluralForm - Plural form string.. - * @return An function to compute plural forms. + * @returns An function to compute plural forms. */ + // eslint-disable-next-line @typescript-eslint/ban-types private getPluralFunc(pluralForm: string): Function { // Plural form string regexp // taken from https://github.com/Orange-OpenSource/gettext.js/blob/master/lib.gettext.js @@ -566,7 +567,7 @@ class Gettext { * Remove the context delimiter from string. * * @param str - Translation string. - * @return A translation string without context. + * @returns A translation string without context. */ private removeContext(str: string): string { // if there is context, remove it @@ -585,7 +586,7 @@ class Gettext { * @param options - Translation options. * @param args - Any variables to interpolate. * - * @return A translation string without context. + * @returns A translation string without context. * * ### Notes * Contains juicy parts of https://github.com/Orange-OpenSource/gettext.js/blob/master/lib.gettext.js diff --git a/packages/translation/src/manager.ts b/packages/translation/src/manager.ts index d719944d447e..0d17de744c54 100644 --- a/packages/translation/src/manager.ts +++ b/packages/translation/src/manager.ts @@ -20,6 +20,10 @@ export class TranslationManager implements ITranslator { this._englishBundle = new Gettext({ stringsPrefix: this._stringsPrefix }); } + get languageCode(): string { + return this._currentLocale; + } + /** * Fetch the localization data from the server. * diff --git a/packages/translation/src/server.ts b/packages/translation/src/server.ts index 0f2f1336a7f6..d50cd20f46f7 100644 --- a/packages/translation/src/server.ts +++ b/packages/translation/src/server.ts @@ -26,7 +26,7 @@ export async function requestTranslationsAPI( // Make request to Jupyter API const settings = serverSettings ?? ServerConnection.makeSettings(); translationsUrl = - translationsUrl || `${settings.appUrl}/${TRANSLATIONS_SETTINGS_URL}/`; + translationsUrl || `${settings.appUrl}/${TRANSLATIONS_SETTINGS_URL}`; const requestUrl = URLExt.join(settings.baseUrl, translationsUrl, locale); let response: Response; try { diff --git a/packages/translation/src/tokens.ts b/packages/translation/src/tokens.ts index 1ed7518bbc96..6695d6b88739 100644 --- a/packages/translation/src/tokens.ts +++ b/packages/translation/src/tokens.ts @@ -3,6 +3,7 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ +import type { IRenderMime } from '@jupyterlab/rendermime-interfaces'; import { ServerConnection } from '@jupyterlab/services'; import { DataConnector, IDataConnector } from '@jupyterlab/statedb'; import { Token } from '@lumino/coreutils'; @@ -11,18 +12,26 @@ import { requestTranslationsAPI } from './server'; /* * Translation */ -type Language = { [key: string]: string }; +export type Language = { [key: string]: string }; +/** + * Translation connection interface. + */ export interface ITranslatorConnector extends IDataConnector {} +/** + * A service to connect to the server translation endpoint + */ export const ITranslatorConnector = new Token( - '@jupyterlab/translation:ITranslatorConnector' + '@jupyterlab/translation:ITranslatorConnector', + 'A service to connect to the server translation endpoint.' ); export class TranslatorConnector extends DataConnector - implements ITranslatorConnector { + implements ITranslatorConnector +{ constructor( translationsUrl: string = '', serverSettings?: ServerConnection.ISettings @@ -46,84 +55,19 @@ export class TranslatorConnector } /** - * Bundle of gettext-based translation functions. - * - * The calls to the functions in this bundle will be automatically - * extracted by `jupyterlab-translate` package to generate translation - * template files if the bundle is assigned to: - * - variable named `trans`, - * - public attribute named `trans` (`this.trans`), - * - private attribute named `trans` (`this._trans`), - * - `trans` attribute `props` variable (`props.trans`), - * - `trans` attribute `props` attribute (`this.props.trans`) + * Bundle of gettext-based translation functions for a specific domain. */ -export type TranslationBundle = { - /** - * Alias for `gettext` (translate strings without number inflection) - * @param msgid message (text to translate) - * @param args - */ - __(msgid: string, ...args: any[]): string; - /** - * Alias for `ngettext` (translate accounting for plural forms) - * @param msgid message for singular - * @param msgid_plural message for plural - * @param n determines which plural form to use - * @param args - */ - _n(msgid: string, msgid_plural: string, n: number, ...args: any[]): string; - /** - * Alias for `pgettext` (translate in given context) - * @param msgctxt context - * @param msgid message (text to translate) - * @param args - */ - _p(msgctxt: string, msgid: string, ...args: any[]): string; - /** - * Alias for `npgettext` (translate accounting for plural forms in given context) - * @param msgctxt context - * @param msgid message for singular - * @param msgid_plural message for plural - * @param n number used to determine which plural form to use - * @param args - */ - _np( - msgctxt: string, - msgid: string, - msgid_plural: string, - n: number, - ...args: any[] - ): string; - gettext(msgid: string, ...args: any[]): string; - ngettext( - msgid: string, - msgid_plural: string, - n: number, - ...args: any[] - ): string; - pgettext(msgctxt: string, msgid: string, ...args: any[]): string; - npgettext( - msgctxt: string, - msgid: string, - msgid_plural: string, - n: number, - ...args: any[] - ): string; - dcnpgettext( - domain: string, - msgctxt: string, - msgid: string, - msgid_plural: string, - n: number, - ...args: any[] - ): string; -}; +export type TranslationBundle = IRenderMime.TranslationBundle; -export interface ITranslator { - load(domain: string): TranslationBundle; - // locale(): string; -} +/** + * Translation provider interface + */ +export interface ITranslator extends IRenderMime.ITranslator {} +/** + * Translation provider token + */ export const ITranslator = new Token( - '@jupyterlab/translation:ITranslator' + '@jupyterlab/translation:ITranslator', + 'A service to translate strings.' ); diff --git a/packages/translation/src/utils.ts b/packages/translation/src/utils.ts index 2abbf128a65b..a5f69f785a30 100644 --- a/packages/translation/src/utils.ts +++ b/packages/translation/src/utils.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + /** * Normalize domain * diff --git a/packages/translation/tsconfig.json b/packages/translation/tsconfig.json index 9a253ba46b2a..ce3030d31bef 100644 --- a/packages/translation/tsconfig.json +++ b/packages/translation/tsconfig.json @@ -9,6 +9,9 @@ { "path": "../coreutils" }, + { + "path": "../rendermime-interfaces" + }, { "path": "../services" }, diff --git a/packages/translation/tsconfig.test.json b/packages/translation/tsconfig.test.json index 4f0b87507cf7..dbab2a159c08 100644 --- a/packages/translation/tsconfig.test.json +++ b/packages/translation/tsconfig.test.json @@ -5,6 +5,9 @@ { "path": "../coreutils" }, + { + "path": "../rendermime-interfaces" + }, { "path": "../services" }, @@ -15,16 +18,7 @@ "path": "." }, { - "path": "../../testutils" - }, - { - "path": "../coreutils" - }, - { - "path": "../services" - }, - { - "path": "../statedb" + "path": "../testing" } ] } diff --git a/packages/ui-components-extension/package.json b/packages/ui-components-extension/package.json index ab66306d44eb..fb81c09b30bf 100644 --- a/packages/ui-components-extension/package.json +++ b/packages/ui-components-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/ui-components-extension", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - UI component plugins", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -23,7 +23,8 @@ }, "files": [ "lib/*.{d.ts,js,js.map}", - "style/*" + "style/*", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -32,13 +33,13 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/ui-components": "^4.0.8" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/ui-components-extension/src/index.ts b/packages/ui-components-extension/src/index.ts index b4df7f3f86f8..dfe50735f50c 100644 --- a/packages/ui-components-extension/src/index.ts +++ b/packages/ui-components-extension/src/index.ts @@ -10,8 +10,8 @@ import { JupyterFrontEndPlugin } from '@jupyterlab/application'; import { - FormComponentRegistry, - IFormComponentRegistry, + FormRendererRegistry, + IFormRendererRegistry, ILabIconManager } from '@jupyterlab/ui-components'; @@ -21,6 +21,7 @@ import { */ const labiconManager: JupyterFrontEndPlugin = { id: '@jupyterlab/ui-components-extension:labicon-manager', + description: 'Provides the icon manager.', provides: ILabIconManager, autoStart: true, activate: (app: JupyterFrontEnd) => { @@ -29,16 +30,18 @@ const labiconManager: JupyterFrontEndPlugin = { }; /** - * Sets up the component registry to be used by the FormEditor component. + * Sets up the renderer registry to be used by the FormEditor component. */ -const registryPlugin: JupyterFrontEndPlugin = { - id: '@jupyterlab/settingeditor-extension:form-registry', - provides: IFormComponentRegistry, - autoStart: true, - activate: (app: JupyterFrontEnd): IFormComponentRegistry => { - const editorRegistry = new FormComponentRegistry(); - return editorRegistry; - } -}; +const formRendererRegistryPlugin: JupyterFrontEndPlugin = + { + id: '@jupyterlab/ui-components-extension:form-renderer-registry', + description: 'Provides the settings form renderer registry.', + provides: IFormRendererRegistry, + autoStart: true, + activate: (app: JupyterFrontEnd): IFormRendererRegistry => { + const formRendererRegistry = new FormRendererRegistry(); + return formRendererRegistry; + } + }; -export default [labiconManager, registryPlugin]; +export default [labiconManager, formRendererRegistryPlugin]; diff --git a/packages/ui-components/.storybook/main.js b/packages/ui-components/.storybook/main.js deleted file mode 100644 index 7462333a9ca3..000000000000 --- a/packages/ui-components/.storybook/main.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - stories: ['../stories/*.stories.tsx'] -}; diff --git a/packages/ui-components/.storybook/tsconfig.json b/packages/ui-components/.storybook/tsconfig.json deleted file mode 100644 index da0d0275bdd2..000000000000 --- a/packages/ui-components/.storybook/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../../tsconfigbase.json", - "compilerOptions": { - "lib": ["es6", "dom", "ES2018"], - "allowJs": false, - "rootDir": "../", - "outDir": "dist", - "noImplicitReturns": true, - "noImplicitThis": true, - "skipLibCheck": true - }, - "include": ["../src/**/*"], - "exclude": ["node_modules"] -} diff --git a/packages/ui-components/.storybook/webpack.config.js b/packages/ui-components/.storybook/webpack.config.js deleted file mode 100644 index 77c800df88a9..000000000000 --- a/packages/ui-components/.storybook/webpack.config.js +++ /dev/null @@ -1,59 +0,0 @@ -const path = require('path'); -const SRC_PATH = path.join(__dirname, '../src'); -const STORIES_PATH = path.join(__dirname, '../stories'); -const crypto = require('crypto'); - -// Workaround for loaders using "md4" by default, which is not supported in FIPS-compliant OpenSSL -const cryptoOrigCreateHash = crypto.createHash; -crypto.createHash = algorithm => - cryptoOrigCreateHash(algorithm == 'md4' ? 'sha256' : algorithm); - -module.exports = ({ config }) => { - // don't use storybook's default svg configuration - // https://github.com/storybookjs/storybook/issues/6758 - config.module.rules = config.module.rules.map(rule => { - if (rule.test.toString().includes('svg')) { - const test = rule.test.toString().replace('svg|', '').replace(/\//g, ''); - return { ...rule, test: new RegExp(test) }; - } else { - return rule; - } - }); - - // ts rules - config.module.rules.push({ - test: /\.(ts|tsx)$/, - // dont need stories path if you have your stories inside your src folder - include: [SRC_PATH, STORIES_PATH], - use: [ - { - loader: require.resolve('ts-loader'), - options: { - configFile: './.storybook/tsconfig.json' - } - } - ] - }); - config.resolve.extensions.push('.ts', '.tsx'); - - // svg rules - config.module.rules.push({ - // in css files, svg is loaded as a url formatted string - test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, - issuer: /\.css$/, - use: { - loader: 'svg-url-loader', - options: { encoding: 'none', limit: 10000 } - } - }); - config.module.rules.push({ - // in js, jsx, ts, and tsx files svg is loaded as a raw string - test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, - issuer: { test: /\.(js|jsx|ts|tsx)$/ }, - use: { - loader: 'raw-loader' - } - }); - - return config; -}; diff --git a/packages/ui-components/.vscode/launch.json b/packages/ui-components/.vscode/launch.json index 3c841b4f2ce8..66fb4b825a88 100644 --- a/packages/ui-components/.vscode/launch.json +++ b/packages/ui-components/.vscode/launch.json @@ -12,4 +12,4 @@ "port": 9229 } ] -} \ No newline at end of file +} diff --git a/packages/ui-components/README.md b/packages/ui-components/README.md index daef31e6d8d6..2baab96cb1b9 100644 --- a/packages/ui-components/README.md +++ b/packages/ui-components/README.md @@ -85,20 +85,20 @@ Alternatively, you can just render the icon directly into any existing DOM node `elem` by using the `ReactDOM` module: ```typescript -ReactDOM.render(jupyterIcon.react, elem); +const root = createRoot(elem); +root.render(jupyterIcon.react); ``` If do you use `ReactDOM` to render, and if the `elem` node is ever removed from the DOM, you’ll first need to clean it up: ```typescript -ReactDOM.unmountComponentAtNode(elem); +root.unmount(); ``` This cleanup step is not a special property of `LabIcon`, but is instead needed for any React component that is rendered directly at the top -level by `ReactDOM`: failure to call `unmountComponentAtNode` can result -in a [memory leak](https://stackoverflow.com/a/48198011/425458). +level by `ReactDOM`. ## How to create your own custom `LabIcon` diff --git a/packages/ui-components/babel.config.js b/packages/ui-components/babel.config.js index 8b5c76420c60..eb2198a956e7 100644 --- a/packages/ui-components/babel.config.js +++ b/packages/ui-components/babel.config.js @@ -1 +1,6 @@ -module.exports = require('@jupyterlab/testutils/lib/babel.config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +module.exports = require('@jupyterlab/testing/lib/babel-config'); diff --git a/packages/ui-components/docs/build.sh b/packages/ui-components/docs/build.sh index 43f8b4c76afa..2bba56b52313 100755 --- a/packages/ui-components/docs/build.sh +++ b/packages/ui-components/docs/build.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + # get this script's parent dir DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" diff --git a/packages/ui-components/docs/source/README.rst b/packages/ui-components/docs/source/README.rst index 3a94999b9b6d..05f6cb3b001a 100644 --- a/packages/ui-components/docs/source/README.rst +++ b/packages/ui-components/docs/source/README.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + @jupyterlab/ui-components ========================= diff --git a/packages/ui-components/docs/source/generated_warning.rst b/packages/ui-components/docs/source/generated_warning.rst index 638492a8c776..aed5d8c63e50 100644 --- a/packages/ui-components/docs/source/generated_warning.rst +++ b/packages/ui-components/docs/source/generated_warning.rst @@ -1,3 +1,6 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. raw:: html + + + + + + {% block title %}{{page_title | e}}{% endblock %} + + {% block favicon %}{% endblock %} + + + + + +{% block stylesheet %} + +{% endblock %} +{% block site %} + +
    + {% block h1_error %} +

    {{status_code | e}} : {{status_message | e}}

    + {% endblock h1_error %} + {% block error_detail %} + {% if message %} +

    The error was:

    +
    +
    {{message | e}}
    +
    + {% endif %} + {% endblock %} + + +{% endblock %} + +{% block script %} + +{% endblock script %} + + + + diff --git a/packages/ui-components/examples/simple-windowed-list/templates/index.html b/packages/ui-components/examples/simple-windowed-list/templates/index.html new file mode 100644 index 000000000000..a83960734f2c --- /dev/null +++ b/packages/ui-components/examples/simple-windowed-list/templates/index.html @@ -0,0 +1,36 @@ + + + + + + {{page_config['appName'] | e}} + + + + {# Copy so we do not modify the page_config with updates. #} + {% set page_config_full = page_config.copy() %} + + {# Set a dummy variable - we just want the side effect of the update. #} + {% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} + + + + + + + + diff --git a/packages/ui-components/examples/simple-windowed-list/tsconfig.json b/packages/ui-components/examples/simple-windowed-list/tsconfig.json new file mode 100644 index 000000000000..c21b188b7842 --- /dev/null +++ b/packages/ui-components/examples/simple-windowed-list/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../../../tsconfigbase", + "compilerOptions": { + "outDir": "build", + "rootDir": "src", + "module": "commonjs", + "strictNullChecks": true, + "types": ["node"] + }, + "include": ["src/**/*"], + "references": [ + { + "path": "../../../application" + }, + { + "path": "../../../coreutils" + }, + { + "path": "../../../observables" + }, + { + "path": "../../../theme-light-extension" + }, + { + "path": "../.." + } + ] +} diff --git a/packages/ui-components/examples/simple-windowed-list/webpack.config.js b/packages/ui-components/examples/simple-windowed-list/webpack.config.js new file mode 100644 index 000000000000..ad033bf565dd --- /dev/null +++ b/packages/ui-components/examples/simple-windowed-list/webpack.config.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const miniSVGDataURI = require('mini-svg-data-uri'); + +module.exports = { + entry: ['./build/index.js'], + output: { + path: __dirname + '/build', + filename: 'bundle.js' + }, + bail: true, + mode: 'development', + module: { + rules: [ + { test: /\.css$/, use: ['style-loader', 'css-loader'] }, + { test: /\.html$/, type: 'asset/resource' }, + { test: /\.js.map$/, type: 'asset/resource' }, + { + // In .css files, svg is loaded as a data URI. + test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, + issuer: /\.css$/, + type: 'asset/inline', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) + } + }, + { + // In .ts and .tsx files (both of which compile to .js), svg files + // must be loaded as a raw string instead of data URIs. + test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, + issuer: /\.js$/, + type: 'asset/source' + } + ] + } +}; diff --git a/packages/ui-components/jest.config.js b/packages/ui-components/jest.config.js index 178440a1c5f3..cd234acbbdc0 100644 --- a/packages/ui-components/jest.config.js +++ b/packages/ui-components/jest.config.js @@ -1,2 +1,7 @@ -const func = require('@jupyterlab/testutils/lib/jest-config'); +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +const func = require('@jupyterlab/testing/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/ui-components/package.json b/packages/ui-components/package.json index f9ba3d460d53..264cd2cadc34 100644 --- a/packages/ui-components/package.json +++ b/packages/ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/ui-components", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - UI components written in React", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -24,70 +24,58 @@ "files": [ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", - "style/index.js" + "style/index.js", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", - "build:storybook": "build-storybook -c .storybook", "build:test": "tsc --build tsconfig.test.json", "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", "cleansvg": "svgo --config svgo.yaml", "docs": "typedoc src", "docs:init": "bash docs/build.sh", - "storybook": "start-storybook -p 9001 -c .storybook", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@blueprintjs/core": "^3.36.0", - "@blueprintjs/select": "^3.15.0", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/translation": "^3.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/commands": "^1.19.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/disposable": "^1.10.0", - "@lumino/signaling": "^1.10.0", - "@lumino/virtualdom": "^1.14.0", - "@lumino/widgets": "^1.37.2", - "@rjsf/core": "^3.1.0", - "react": "^17.0.1", - "react-dom": "^17.0.1", + "@jupyterlab/coreutils": "^6.0.8", + "@jupyterlab/observables": "^5.0.8", + "@jupyterlab/rendermime-interfaces": "^3.8.8", + "@jupyterlab/translation": "^4.0.8", + "@lumino/algorithm": "^2.0.1", + "@lumino/commands": "^2.1.3", + "@lumino/coreutils": "^2.1.2", + "@lumino/disposable": "^2.1.2", + "@lumino/messaging": "^2.0.1", + "@lumino/polling": "^2.1.2", + "@lumino/properties": "^2.0.1", + "@lumino/signaling": "^2.1.2", + "@lumino/virtualdom": "^2.0.1", + "@lumino/widgets": "^2.3.0", + "@rjsf/core": "^5.1.0", + "@rjsf/utils": "^5.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", "typestyle": "^2.0.4" }, "devDependencies": { - "@babel/core": "^7.10.2", - "@babel/preset-env": "^7.10.2", - "@jupyterlab/testutils": "^3.6.6", - "@storybook/addon-actions": "6.0.20", - "@storybook/react": "6.0.20", - "@types/jest": "^26.0.10", - "@types/react": "^17.0.0", - "@types/webpack-env": "^1.14.1", - "babel-loader": "^8.0.6", - "jest": "^26.4.2", + "@jupyterlab/testing": "^4.0.8", + "@types/jest": "^29.2.0", + "@types/react": "^18.0.26", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "svgo": "^1.3.2", - "ts-jest": "^26.3.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "svgo": "^3.0.1", + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "peerDependencies": { - "react": "^17.0.1" + "react": "^18.2.0" }, "publishConfig": { "access": "public" }, - "jupyterlab": { - "extraStyles": { - "blueprintjs": [ - "icons/lib/css/blueprint-icons.css", - "core/lib/css/blueprint.css" - ] - } - }, "styleModule": "style/index.js" } diff --git a/packages/ui-components/src/FormRendererRegistry.tsx b/packages/ui-components/src/FormRendererRegistry.tsx new file mode 100644 index 000000000000..fef9289ab4ce --- /dev/null +++ b/packages/ui-components/src/FormRendererRegistry.tsx @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------------------- +| Copyright (c) Jupyter Development Team. +| Distributed under the terms of the Modified BSD License. +|----------------------------------------------------------------------------*/ + +import { IFormRenderer, IFormRendererRegistry } from './tokens'; + +/** + * A registry for property renderers used in the FormEditor component. + */ +export class FormRendererRegistry implements IFormRendererRegistry { + /** + * Adds a renderer for a given property of a given settings plugin. + * + * The id must follow that structure `.` + * + * @param id - Unique ID for the given renderer. + * @param renderer - A renderer interfacing IFormRenderer. + */ + addRenderer(id: string, renderer: IFormRenderer): void { + if (this._renderers[id]) { + throw new Error(`A renderer with id '${id}' is already registered.`); + } + if (!renderer.fieldRenderer && !renderer.widgetRenderer) { + throw new Error( + `The component for '${id}' cannot be registered as it does not define 'fieldRenderer' nor 'widgetRenderer'.` + ); + } + + const splitPosition = id.lastIndexOf('.'); + const pluginId = id.substring(0, splitPosition); + const propertyName = id.substring(splitPosition + 1); + if (pluginId.length == 0 || propertyName.length == 0) { + throw new Error( + `Form renderer id must follows the structure '.'; got ${id}.` + ); + } + + this._renderers[id] = renderer; + } + + /** + * Returns all registered renderers in dictionary form. + * @returns - A dictionary that maps an id to a renderer. + */ + get renderers(): { [id: string]: IFormRenderer } { + return this._renderers; + } + + /** + * Returns the renderer for the given id + * @param id - The unique id for the renderer. + * @returns - A renderer interfacing IFormRenderer. + */ + getRenderer(id: string): IFormRenderer { + return this._renderers[id]; + } + + private _renderers: { [id: string]: IFormRenderer } = {}; +} diff --git a/packages/ui-components/src/blueprint.tsx b/packages/ui-components/src/blueprint.tsx deleted file mode 100644 index 85697f60443c..000000000000 --- a/packages/ui-components/src/blueprint.tsx +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { - Button as BPButton, - IButtonProps as IBPButtonProps -} from '@blueprintjs/core/lib/cjs/components/button/buttons'; -import { - Collapse as BPCollapse, - ICollapseProps -} from '@blueprintjs/core/lib/cjs/components/collapse/collapse'; -import { - Checkbox as BPCheckbox, - ICheckboxProps -} from '@blueprintjs/core/lib/cjs/components/forms/controls'; -import { - InputGroup as BPInputGroup, - IInputGroupProps as IBPInputGroupProps -} from '@blueprintjs/core/lib/cjs/components/forms/inputGroup'; -import { - Select as BPSelect, - ISelectProps -} from '@blueprintjs/select/lib/cjs/components/select/select'; -import * as React from 'react'; -import { LabIcon } from './icon'; -import { classes } from './utils'; -export { Intent } from '@blueprintjs/core/lib/cjs/common/intent'; - -interface IButtonProps extends IBPButtonProps { - title?: string; - type?: 'button' | 'submit' | 'reset'; -} - -interface IInputGroupProps extends IBPInputGroupProps { - rightIcon?: string; -} - -type CommonProps = React.DOMAttributes; - -export const Button = (props: IButtonProps & CommonProps) => ( - -); - -export const InputGroup = (props: IInputGroupProps & CommonProps) => { - if (props.rightIcon) { - return ( - - -
    - } - /> - ); - } - return ( - - ); -}; - -export const Collapse = (props: ICollapseProps & CommonProps) => ( - -); - -export const Select = (props: ISelectProps & CommonProps) => ( - -); - -export const Checkbox = (props: ICheckboxProps & CommonProps) => ( - -); diff --git a/packages/ui-components/src/components/accordiontoolbar.ts b/packages/ui-components/src/components/accordiontoolbar.ts new file mode 100644 index 000000000000..5273921b2c6d --- /dev/null +++ b/packages/ui-components/src/components/accordiontoolbar.ts @@ -0,0 +1,252 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { Message, MessageLoop } from '@lumino/messaging'; +import { + AccordionLayout, + AccordionPanel, + Title, + Widget +} from '@lumino/widgets'; +import { caretDownIcon } from '../icon'; +import { Toolbar } from './toolbar'; + +/** + * Accordion panel layout that adds a toolbar in widget title if present. + */ +class AccordionToolbarLayout extends AccordionLayout { + /** + * Insert a widget into the layout at the specified index. + * + * @param index - The index at which to insert the widget. + * + * @param widget - The widget to insert into the layout. + * + * #### Notes + * The index will be clamped to the bounds of the widgets. + * + * If the widget is already added to the layout, it will be moved. + * + * #### Undefined Behavior + * An `index` which is non-integral. + */ + insertWidget(index: number, widget: Toolbar.IWidgetToolbar): void { + if (widget.toolbar) { + this._toolbars.set(widget, widget.toolbar); + widget.toolbar.addClass('jp-AccordionPanel-toolbar'); + } + super.insertWidget(index, widget); + } + + /** + * Remove the widget at a given index from the layout. + * + * @param index - The index of the widget to remove. + * + * #### Notes + * A widget is automatically removed from the layout when its `parent` + * is set to `null`. This method should only be invoked directly when + * removing a widget from a layout which has yet to be installed on a + * parent widget. + * + * This method does *not* modify the widget's `parent`. + * + * #### Undefined Behavior + * An `index` which is non-integral. + */ + removeWidgetAt(index: number): void { + const widget = this.widgets[index]; + super.removeWidgetAt(index); + // Remove the toolbar after the widget has `removeWidgetAt` will call `detachWidget` + if (widget && this._toolbars.has(widget)) { + this._toolbars.delete(widget); + } + } + + /** + * Attach a widget to the parent's DOM node. + * + * @param index - The current index of the widget in the layout. + * + * @param widget - The widget to attach to the parent. + */ + protected attachWidget(index: number, widget: Widget): void { + super.attachWidget(index, widget); + + const toolbar = this._toolbars.get(widget); + if (toolbar) { + // Send a `'before-attach'` message if the parent is attached. + if (this.parent!.isAttached) { + MessageLoop.sendMessage(toolbar, Widget.Msg.BeforeAttach); + } + + // Insert the toolbar in the title node. + this.titles[index].appendChild(toolbar.node); + + // Send an `'after-attach'` message if the parent is attached. + if (this.parent!.isAttached) { + MessageLoop.sendMessage(toolbar, Widget.Msg.AfterAttach); + } + } + } + + /** + * Detach a widget from the parent's DOM node. + * + * @param index - The previous index of the widget in the layout. + * + * @param widget - The widget to detach from the parent. + */ + protected detachWidget(index: number, widget: Widget): void { + const toolbar = this._toolbars.get(widget); + if (toolbar) { + // Send a `'before-detach'` message if the parent is attached. + if (this.parent!.isAttached) { + MessageLoop.sendMessage(toolbar, Widget.Msg.BeforeDetach); + } + + // Remove the toolbar in the title node. + this.titles[index].removeChild(toolbar.node); + + // Send an `'after-detach'` message if the parent is attached. + if (this.parent!.isAttached) { + MessageLoop.sendMessage(toolbar, Widget.Msg.AfterDetach); + } + } + + super.detachWidget(index, widget); + } + + /** + * A message handler invoked on a `'before-attach'` message. + * + * #### Notes + * The default implementation of this method forwards the message + * to all widgets. It assumes all widget nodes are attached to the + * parent widget node. + * + * This may be reimplemented by subclasses as needed. + */ + protected onBeforeAttach(msg: Message): void { + this.notifyToolbars(msg); + super.onBeforeAttach(msg); + } + + /** + * A message handler invoked on an `'after-attach'` message. + * + * #### Notes + * The default implementation of this method forwards the message + * to all widgets. It assumes all widget nodes are attached to the + * parent widget node. + * + * This may be reimplemented by subclasses as needed. + */ + protected onAfterAttach(msg: Message): void { + super.onAfterAttach(msg); + this.notifyToolbars(msg); + } + + /** + * A message handler invoked on a `'before-detach'` message. + * + * #### Notes + * The default implementation of this method forwards the message + * to all widgets. It assumes all widget nodes are attached to the + * parent widget node. + * + * This may be reimplemented by subclasses as needed. + */ + protected onBeforeDetach(msg: Message): void { + this.notifyToolbars(msg); + super.onBeforeDetach(msg); + } + + /** + * A message handler invoked on an `'after-detach'` message. + * + * #### Notes + * The default implementation of this method forwards the message + * to all widgets. It assumes all widget nodes are attached to the + * parent widget node. + * + * This may be reimplemented by subclasses as needed. + */ + protected onAfterDetach(msg: Message): void { + super.onAfterDetach(msg); + this.notifyToolbars(msg); + } + + private notifyToolbars(msg: Message): void { + this.widgets.forEach(widget => { + const toolbar = this._toolbars.get(widget); + if (toolbar) { + toolbar.processMessage(msg); + } + }); + } + + protected _toolbars = new WeakMap(); +} + +export namespace AccordionToolbar { + /** + * Custom renderer for the SidePanel + */ + export class Renderer extends AccordionPanel.Renderer { + /** + * Render the collapse indicator for a section title. + * + * @param data - The data to use for rendering the section title. + * + * @returns A element representing the collapse indicator. + */ + createCollapseIcon(data: Title): HTMLElement { + const iconDiv = document.createElement('div'); + caretDownIcon.element({ + container: iconDiv + }); + return iconDiv; + } + + /** + * Render the element for a section title. + * + * @param data - The data to use for rendering the section title. + * + * @returns A element representing the section title. + */ + createSectionTitle(data: Title): HTMLElement { + const handle = super.createSectionTitle(data); + handle.classList.add('jp-AccordionPanel-title'); + return handle; + } + } + + export const defaultRenderer = new Renderer(); + + /** + * Create an accordion layout for accordion panel with toolbar in the title. + * + * @param options Panel options + * @returns Panel layout + * + * #### Note + * + * Default titleSpace is 29 px (default var(--jp-private-toolbar-height) - but not styled) + */ + export function createLayout( + options: AccordionPanel.IOptions + ): AccordionLayout { + return ( + options.layout || + new AccordionToolbarLayout({ + renderer: options.renderer || defaultRenderer, + orientation: options.orientation, + alignment: options.alignment, + spacing: options.spacing, + titleSpace: options.titleSpace ?? 29 + }) + ); + } +} diff --git a/packages/ui-components/src/components/button.tsx b/packages/ui-components/src/components/button.tsx new file mode 100644 index 000000000000..779b015dff04 --- /dev/null +++ b/packages/ui-components/src/components/button.tsx @@ -0,0 +1,45 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import React from 'react'; +import { classes } from '../utils'; + +/** + * Button component property + */ +export interface IButtonProps + extends React.ButtonHTMLAttributes { + /** + * Whether this button should use minimal styles. + */ + minimal?: boolean; + /** + * Whether this button should use small styles. + */ + small?: boolean; +} + +/** + * Button component + * + * @param props Component properties + * @returns Component + */ +export function Button(props: IButtonProps): JSX.Element { + const { minimal, small, children, ...others } = props; + return ( + + ); +} diff --git a/packages/apputils/src/collapse.ts b/packages/ui-components/src/components/collapser.ts similarity index 71% rename from packages/apputils/src/collapse.ts rename to packages/ui-components/src/components/collapser.ts index 5c5accebb83f..6ac4f376fdcd 100644 --- a/packages/apputils/src/collapse.ts +++ b/packages/ui-components/src/components/collapser.ts @@ -1,25 +1,51 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { caretDownIcon, caretUpIcon } from '@jupyterlab/ui-components'; import { Message } from '@lumino/messaging'; import { ISignal, Signal } from '@lumino/signaling'; import { Panel, PanelLayout, Title, Widget } from '@lumino/widgets'; +import { caretDownIcon } from '../icon'; + +const COLLAPSE_CLASS = 'jp-Collapse'; + +const CONTENTS_CLASS = 'jp-Collapse-contents'; + +const HEADER_CLASS = 'jp-Collapse-header'; + +const HEADER_COLLAPSED_CLASS = 'jp-Collapse-header-collapsed'; + +const ICON_CLASS = 'jp-Collapser-icon'; + +const TITLE_CLASS = 'jp-Collapser-title'; + /** * A panel that supports a collapsible header made from the widget's title. * Clicking on the title expands or contracts the widget. */ -export class Collapse extends Widget { - constructor(options: Collapse.IOptions) { +export class Collapser extends Widget { + constructor(options: Collapser.IOptions) { super(options); const { widget, collapsed = true } = options; - this.addClass('jp-Collapse'); + this.addClass(COLLAPSE_CLASS); this._header = new Widget(); - this._header.addClass('jp-Collapse-header'); + this._header.addClass(HEADER_CLASS); + if (collapsed) { + this._header.addClass(HEADER_COLLAPSED_CLASS); + } + this._header.node.appendChild( + caretDownIcon.element({ + className: ICON_CLASS + }) + ); + const titleSpan = document.createElement('span'); + titleSpan.classList.add(TITLE_CLASS); + titleSpan.textContent = widget.title.label; + this._header.node.appendChild(titleSpan); + this._content = new Panel(); - this._content.addClass('jp-Collapse-contents'); + this._content.addClass(CONTENTS_CLASS); const layout = new PanelLayout(); this.layout = layout; @@ -51,7 +77,7 @@ export class Collapse extends Widget { /** * The collapsed state of the panel. */ - get collapsed() { + get collapsed(): boolean { return this._collapsed; } set collapsed(value: boolean) { @@ -68,21 +94,21 @@ export class Collapse extends Widget { /** * A signal for when the widget collapse state changes. */ - get collapseChanged(): ISignal { + get collapseChanged(): ISignal { return this._collapseChanged; } /** * Toggle the collapse state of the panel. */ - toggle() { + toggle(): void { this.collapsed = !this.collapsed; } /** * Dispose the widget. */ - dispose() { + dispose(): void { if (this.isDisposed) { return; } @@ -96,7 +122,7 @@ export class Collapse extends Widget { } /** - * Handle the DOM events for the Collapse widget. + * Handle the DOM events for the Collapser widget. * * @param event - The DOM event sent to the panel. * @@ -115,11 +141,11 @@ export class Collapse extends Widget { } } - protected onAfterAttach(msg: Message) { + protected onAfterAttach(msg: Message): void { this._header.node.addEventListener('click', this); } - protected onBeforeDetach(msg: Message) { + protected onBeforeDetach(msg: Message): void { this._header.node.removeEventListener('click', this); } @@ -153,12 +179,11 @@ export class Collapse extends Widget { } private _setHeader(): void { - (this._collapsed ? caretUpIcon : caretDownIcon).element({ - container: this._header.node, - label: this._widget.title.label, - elementPosition: 'right', - height: '28px' - }); + if (this._collapsed) { + this._header.addClass(HEADER_COLLAPSED_CLASS); + } else { + this._header.removeClass(HEADER_COLLAPSED_CLASS); + } } private _collapseChanged = new Signal(this); @@ -168,7 +193,7 @@ export class Collapse extends Widget { private _widget: T; } -export namespace Collapse { +export namespace Collapser { export interface IOptions extends Widget.IOptions { widget: T; collapsed?: boolean; diff --git a/packages/ui-components/src/components/form.tsx b/packages/ui-components/src/components/form.tsx new file mode 100644 index 000000000000..079aa5dd7640 --- /dev/null +++ b/packages/ui-components/src/components/form.tsx @@ -0,0 +1,678 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { ITranslator, nullTranslator } from '@jupyterlab/translation'; +import { JSONExt, ReadonlyJSONObject } from '@lumino/coreutils'; + +import Form, { FormProps, IChangeEvent } from '@rjsf/core'; + +import { + ADDITIONAL_PROPERTY_FLAG, + ArrayFieldTemplateProps, + canExpand, + FieldTemplateProps, + getTemplate, + ObjectFieldTemplateProps, + Registry, + UiSchema +} from '@rjsf/utils'; + +import React from 'react'; +import { + addIcon, + caretDownIcon, + caretUpIcon, + closeIcon, + LabIcon +} from '../icon'; + +/** + * Default `ui:options` for the UiSchema. + */ +export const DEFAULT_UI_OPTIONS = { + /** + * This prevents the submit button from being rendered, by default, as it is + * almost never what is wanted. + * + * Provide any `uiSchema#/ui:options/submitButtonOptions` to override this. + */ + submitButtonOptions: { + norender: true + } +}; + +/** + * Form component namespace. + */ +export namespace FormComponent { + export interface IButtonProps { + /** + * Button style. + */ + buttonStyle?: 'icons' | 'text'; + /** + * Translator for button text. + */ + translator?: ITranslator; + } + + /** + * Properties for React JSON schema form's container template (array and object). + */ + export interface ILabCustomizerProps extends IButtonProps { + /** + * Whether the container is in compact mode or not. + * In compact mode the title and description are displayed more compactness. + */ + compact?: boolean; + /** + * Whether to display if the current value is not the default one. + */ + showModifiedFromDefault?: boolean; + } + + /** + * Properties of the button to move an item. + */ + export interface IMoveButtonProps extends IButtonProps { + /** + * Item index to move with this button. + */ + item: ArrayFieldTemplateProps['items'][number]; + /** + * Direction in which to move the item. + */ + direction: 'up' | 'down'; + } + + /** + * Properties of the button to drop an item. + */ + export interface IDropButtonProps extends IButtonProps { + /** + * Item index to drop with this button. + */ + item: ArrayFieldTemplateProps['items'][number]; + } + + /** + * Properties of the button to add an item. + */ + export interface IAddButtonProps extends IButtonProps { + /** + * Function to call to add an item. + */ + onAddClick: ArrayFieldTemplateProps['onAddClick']; + } +} +/** + * Button to move an item. + * + * @returns - the button as a react element. + */ +export const MoveButton = ( + props: FormComponent.IMoveButtonProps +): JSX.Element => { + const trans = (props.translator ?? nullTranslator).load('jupyterlab'); + let buttonContent: JSX.Element | string; + + /** + * Whether the button is disabled or not. + */ + const disabled = () => { + if (props.direction === 'up') { + return !props.item.hasMoveUp; + } else { + return !props.item.hasMoveDown; + } + }; + + if (props.buttonStyle === 'icons') { + const iconProps: LabIcon.IReactProps = { + tag: 'span', + elementSize: 'xlarge', + elementPosition: 'center' + }; + buttonContent = + props.direction === 'up' ? ( + + ) : ( + + ); + } else { + buttonContent = + props.direction === 'up' ? trans.__('Move up') : trans.__('Move down'); + } + + const moveTo = + props.direction === 'up' ? props.item.index - 1 : props.item.index + 1; + + return ( + + ); +}; + +/** + * Button to drop an item. + * + * @returns - the button as a react element. + */ +export const DropButton = ( + props: FormComponent.IDropButtonProps +): JSX.Element => { + const trans = (props.translator ?? nullTranslator).load('jupyterlab'); + let buttonContent: JSX.Element | string; + + if (props.buttonStyle === 'icons') { + buttonContent = ( + + ); + } else { + buttonContent = trans.__('Remove'); + } + + return ( + + ); +}; + +/** + * Button to add an item. + * + * @returns - the button as a react element. + */ +export const AddButton = ( + props: FormComponent.IAddButtonProps +): JSX.Element => { + const trans = (props.translator ?? nullTranslator).load('jupyterlab'); + let buttonContent: JSX.Element | string; + + if (props.buttonStyle === 'icons') { + buttonContent = ( + + ); + } else { + buttonContent = trans.__('Add'); + } + + return ( + + ); +}; + +export interface ILabCustomizerOptions

    + extends FormComponent.ILabCustomizerProps { + name?: string; + component: React.FunctionComponent< + P & Required + >; +} + +function customizeForLab

    ( + options: ILabCustomizerOptions

    +): React.FunctionComponent

    { + const { + component, + name, + buttonStyle, + compact, + showModifiedFromDefault, + translator + } = options; + + const isCompact = compact ?? false; + const button = buttonStyle ?? (isCompact ? 'icons' : 'text'); + + const factory = (props: P) => + component({ + ...props, + buttonStyle: button, + compact: isCompact, + showModifiedFromDefault: showModifiedFromDefault ?? true, + translator: translator ?? nullTranslator + }); + if (name) { + factory.displayName = name; + } + return factory; +} + +/** + * Fetch field templates from RJSF. + */ +function getTemplates(registry: Registry, uiSchema: UiSchema | undefined) { + const TitleField = getTemplate<'TitleFieldTemplate'>( + 'TitleFieldTemplate', + registry, + uiSchema + ); + + const DescriptionField = getTemplate<'DescriptionFieldTemplate'>( + 'DescriptionFieldTemplate', + registry, + uiSchema + ); + + return { TitleField, DescriptionField }; +} + +/** + * Template to allow for custom buttons to re-order/remove entries in an array. + * Necessary to create accessible buttons. + */ +const CustomArrayTemplateFactory = ( + options: FormComponent.ILabCustomizerProps +) => + customizeForLab({ + ...options, + name: 'JupyterLabArrayTemplate', + component: props => { + const { schema, registry, uiSchema, required } = props; + const commonProps = { schema, registry, uiSchema, required }; + const { TitleField, DescriptionField } = getTemplates(registry, uiSchema); + + return ( +

    + {props.compact ? ( +
    +
    + {props.title || ''} +
    +
    + {props.schema.description || ''} +
    +
    + ) : ( + <> + {props.title && ( + + )} + + + )} + {props.items.map(item => { + return ( +
    + {item.children} +
    + + + +
    +
    + ); + })} + {props.canAdd && ( + + )} +
    + ); + } + }); + +/** + * Template with custom add button, necessary for accessibility and internationalization. + */ +const CustomObjectTemplateFactory = ( + options: FormComponent.ILabCustomizerProps +) => + customizeForLab({ + ...options, + name: 'JupyterLabObjectTemplate', + component: props => { + const { schema, registry, uiSchema, required } = props; + const commonProps = { schema, registry, uiSchema, required }; + const { TitleField, DescriptionField } = getTemplates(registry, uiSchema); + + return ( +
    + {props.compact ? ( +
    +
    + {props.title || ''} +
    +
    + {props.schema.description || ''} +
    +
    + ) : ( + <> + {(props.title || + (props.uiSchema || JSONExt.emptyObject)['ui:title']) && ( + + )} + + + )} + {props.properties.map(property => property.content)} + {canExpand(props.schema, props.uiSchema, props.formData) && ( + + )} +
    + ); + } + }); + +/** + * Renders the modified indicator and errors + */ +const CustomTemplateFactory = (options: FormComponent.ILabCustomizerProps) => + customizeForLab({ + ...options, + name: 'JupyterLabFieldTemplate', + component: props => { + const trans = (props.translator ?? nullTranslator).load('jupyterlab'); + let isModified = false; + let defaultValue: any; + const { + formData, + schema, + label, + displayLabel, + id, + formContext, + errors, + rawErrors, + children, + onKeyChange, + onDropPropertyClick + } = props; + + const { defaultFormData } = formContext; + const schemaIds = id.split('_'); + schemaIds.shift(); + const schemaId = schemaIds.join('.'); + + const isRoot = schemaId === ''; + + const hasCustomField = + schemaId === (props.uiSchema || JSONExt.emptyObject)['ui:field']; + + if (props.showModifiedFromDefault) { + /** + * Determine if the field has been modified. + * Schema Id is formatted as 'root_.' + * This logic parses out the field name to find the default value + * before determining if the field has been modified. + */ + + defaultValue = schemaIds.reduce( + (acc, key) => acc?.[key], + defaultFormData + ); + isModified = + !isRoot && + formData !== undefined && + defaultValue !== undefined && + !schema.properties && + schema.type !== 'array' && + !JSONExt.deepEqual(formData, defaultValue); + } + + const needsDescription = + !isRoot && + schema.type != 'object' && + id != + 'jp-SettingsEditor-@jupyterlab/shortcuts-extension:shortcuts_shortcuts'; + + // While we can implement "remove" button for array items in array template, + // object templates do not provide a way to do this instead we need to add + // buttons here (and first check if the field can be removed = is additional). + const isAdditional = schema.hasOwnProperty(ADDITIONAL_PROPERTY_FLAG); + + const isItem: boolean = !( + schema.type === 'object' || schema.type === 'array' + ); + + return ( +
    + {!hasCustomField && + (rawErrors ? ( + // Shows a red indicator for fields that have validation errors +
    + ) : ( + // Only show the modified indicator if there are no errors + isModified &&
    + ))} +
    + {isItem && displayLabel && !isRoot && label && !isAdditional ? ( + props.compact ? ( +
    +
    + {label} +
    + {isItem && schema.description && needsDescription && ( +
    + {schema.description} +
    + )} +
    + ) : ( +

    + {label} +

    + ) + ) : ( + <> + )} + {isAdditional && ( + onKeyChange(event.target.value)} + defaultValue={label} + /> + )} +
    + {children} +
    + {isAdditional && ( + + )} + {!props.compact && schema.description && needsDescription && ( +
    + {schema.description} +
    + )} + {isModified && defaultValue !== undefined && ( +
    + {trans.__( + 'Default: %1', + defaultValue !== null ? defaultValue.toLocaleString() : 'null' + )} +
    + )} +
    {errors}
    +
    +
    + ); + } + }); + +/** + * FormComponent properties + */ +export interface IFormComponentProps + extends FormProps, + FormComponent.ILabCustomizerProps { + /** + * + */ + formData: T; + /** + * + */ + onChange: (e: IChangeEvent) => any; + /** + * + */ + formContext?: unknown; +} + +/** + * Generic rjsf form component for JupyterLab UI. + */ +export function FormComponent(props: IFormComponentProps): JSX.Element { + const { + buttonStyle, + compact, + showModifiedFromDefault, + translator, + formContext, + ...others + } = props; + + const uiSchema = { ...(others.uiSchema || JSONExt.emptyObject) } as UiSchema; + + uiSchema['ui:options'] = { ...DEFAULT_UI_OPTIONS, ...uiSchema['ui:options'] }; + + others.uiSchema = uiSchema; + + const { FieldTemplate, ArrayFieldTemplate, ObjectFieldTemplate } = + props.templates || JSONExt.emptyObject; + + const customization = { + buttonStyle, + compact, + showModifiedFromDefault, + translator + }; + + const fieldTemplate = React.useMemo( + () => FieldTemplate ?? CustomTemplateFactory(customization), + [FieldTemplate, buttonStyle, compact, showModifiedFromDefault, translator] + ) as React.FunctionComponent; + + const arrayTemplate = React.useMemo( + () => ArrayFieldTemplate ?? CustomArrayTemplateFactory(customization), + [ + ArrayFieldTemplate, + buttonStyle, + compact, + showModifiedFromDefault, + translator + ] + ) as React.FunctionComponent; + + const objectTemplate = React.useMemo( + () => ObjectFieldTemplate ?? CustomObjectTemplateFactory(customization), + [ + ObjectFieldTemplate, + buttonStyle, + compact, + showModifiedFromDefault, + translator + ] + ) as React.FunctionComponent; + + const templates: Record = { + FieldTemplate: fieldTemplate, + ArrayFieldTemplate: arrayTemplate, + ObjectFieldTemplate: objectTemplate + }; + + return ( + + ); +} diff --git a/packages/ui-components/src/components/htmlselect.tsx b/packages/ui-components/src/components/htmlselect.tsx index 4dc117c25a48..2dc2eda8685c 100644 --- a/packages/ui-components/src/components/htmlselect.tsx +++ b/packages/ui-components/src/components/htmlselect.tsx @@ -43,7 +43,7 @@ export interface IHTMLSelectProps } export class HTMLSelect extends React.Component { - public render() { + public render(): JSX.Element { const { className, defaultStyle = true, diff --git a/packages/apputils/src/iframe.ts b/packages/ui-components/src/components/iframe.ts similarity index 98% rename from packages/apputils/src/iframe.ts rename to packages/ui-components/src/components/iframe.ts index 3c47450caf87..f3503664770f 100644 --- a/packages/apputils/src/iframe.ts +++ b/packages/ui-components/src/components/iframe.ts @@ -4,7 +4,7 @@ import { Widget } from '@lumino/widgets'; /** - * A phosphor widget which wraps an IFrame. + * A Lumino widget which wraps an IFrame. */ export class IFrame extends Widget { /** diff --git a/packages/ui-components/src/components/index.ts b/packages/ui-components/src/components/index.ts index f417ac256180..ef16a5bfcd76 100644 --- a/packages/ui-components/src/components/index.ts +++ b/packages/ui-components/src/components/index.ts @@ -1,7 +1,20 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. +export * from './button'; +export * from './collapser'; +export * from './form'; export * from './htmlselect'; +export * from './iframe'; +export * from './inputgroup'; export * from './interface'; export * from './menu'; +export * from './panelwithtoolbar'; +export * from './search'; +export * from './sidepanel'; +export * from './spinner'; +export * from './styling'; export * from './switch'; +export * from './toolbar'; +export * from './vdom'; +export * from './windowedlist'; diff --git a/packages/ui-components/src/components/inputgroup.tsx b/packages/ui-components/src/components/inputgroup.tsx new file mode 100644 index 000000000000..447329a63268 --- /dev/null +++ b/packages/ui-components/src/components/inputgroup.tsx @@ -0,0 +1,51 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import React from 'react'; +import { LabIcon } from '../icon'; +import { classes } from '../utils'; + +/** + * InputGroup component properties + */ +export interface IInputGroupProps + extends React.InputHTMLAttributes { + /** + * Pass a ref to the input element + */ + inputRef?: React.RefObject; + /** + * Right icon adornment + */ + rightIcon?: string | LabIcon; +} + +/** + * InputGroup component + * + * @param props Component properties + * @returns Component + */ +export function InputGroup(props: IInputGroupProps): JSX.Element { + const { className, inputRef, rightIcon, ...others } = props; + return ( +
    + + {rightIcon && ( + + {typeof rightIcon === 'string' ? ( + + ) : ( + + )} + + )} +
    + ); +} diff --git a/packages/ui-components/src/components/menu.ts b/packages/ui-components/src/components/menu.ts index e15d413ed2ce..14b57ab73029 100644 --- a/packages/ui-components/src/components/menu.ts +++ b/packages/ui-components/src/components/menu.ts @@ -43,24 +43,15 @@ export interface IRankedMenu extends IDisposable { * * @param options - The options for creating the menu item. * - * @returns The menu item added to the menu. - * - * @deprecated It will return a `IDisposable` object in v4 + * @returns The disposable menu item added to the menu. */ - addItem(options: IRankedMenu.IItemOptions): Menu.IItem; + addItem(options: IRankedMenu.IItemOptions): IDisposable; /** * A read-only array of the menu items in the menu. */ readonly items: ReadonlyArray; - /** - * The underlying Lumino menu. - * - * @deprecated will be removed in v4 - */ - readonly menu: Menu; - /** * Menu rank */ @@ -119,16 +110,6 @@ export class RankedMenu extends Menu implements IRankedMenu { this._includeSeparators = options.includeSeparators ?? true; } - /** - * The underlying Lumino menu. - * - * @deprecated since v3.1 - * RankMenu inherits from Menu since v3.1 - */ - get menu(): Menu { - return this; - } - /** * Menu rank. */ @@ -169,7 +150,7 @@ export class RankedMenu extends Menu implements IRankedMenu { const added: IDisposableMenuItem[] = []; // Insert a separator before the group. - // Phosphor takes care of superfluous leading, + // Lumino takes care of superfluous leading, // trailing, and duplicate separators. if (this._includeSeparators) { added.push( @@ -363,11 +344,7 @@ class DisposableMenuItem implements IDisposableMenuItem { /** * The icon renderer for the menu item. */ - get icon(): - | VirtualElement.IRenderer - | undefined - /* */ - | string /* */ { + get icon(): VirtualElement.IRenderer | undefined { return this._item.deref()!.icon; } diff --git a/packages/ui-components/src/components/panelwithtoolbar.ts b/packages/ui-components/src/components/panelwithtoolbar.ts new file mode 100644 index 000000000000..a1a16c3bbd01 --- /dev/null +++ b/packages/ui-components/src/components/panelwithtoolbar.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { Panel } from '@lumino/widgets'; +import { Toolbar } from './toolbar'; + +/** + * A base class for panel widget with toolbar. + */ +export class PanelWithToolbar extends Panel implements Toolbar.IWidgetToolbar { + constructor(options: PanelWithToolbar.IOptions = {}) { + super(options); + this._toolbar = new Toolbar(); + } + + /** + * Widget toolbar + */ + get toolbar(): Toolbar { + return this._toolbar; + } + + protected _toolbar: Toolbar; +} + +/** + * Namespace for panel with toolbar + */ +export namespace PanelWithToolbar { + /** + * An options object for creating a panel with toolbar widget. + */ + export interface IOptions extends Panel.IOptions { + /** + * Custom toolbar + */ + toolbar?: Toolbar; + } +} diff --git a/packages/apputils/src/search.tsx b/packages/ui-components/src/components/search.tsx similarity index 89% rename from packages/apputils/src/search.tsx rename to packages/ui-components/src/components/search.tsx index b6109407baa3..f41c3bfb2922 100644 --- a/packages/apputils/src/search.tsx +++ b/packages/ui-components/src/components/search.tsx @@ -1,47 +1,57 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { InputGroup } from '@jupyterlab/ui-components'; +import { InputGroup } from './inputgroup'; +import { ReactWidget } from './vdom'; import { StringExt } from '@lumino/algorithm'; import React, { useEffect, useState } from 'react'; -import { ReactWidget } from './vdom'; /** * The class name added to the filebrowser crumbs node. */ export interface IFilterBoxProps { /** - * A function to callback when filter is updated. + * Whether to use case-sensitive search */ - updateFilter: ( - filterFn: (item: string) => boolean | Partial | null, - query?: string - ) => void; + caseSensitive?: boolean; /** - * Whether to use the fuzzy filter. + * Whether the search box is disabled or not. */ - useFuzzyFilter: boolean; + disabled?: boolean; /** - * Optional placeholder for the search box. + * Whether to force a refresh. */ - placeholder?: string; + forceRefresh?: boolean; /** - * Whether to force a refresh. + * An optional initial search value. */ - forceRefresh?: boolean; + initialQuery?: string; /** - * Whether to use case-sensitive search + * Pass a ref to the input element */ - caseSensitive?: boolean; + inputRef?: React.RefObject; /** - * An optional initial search value. + * Optional placeholder for the search box. */ - initialQuery?: string; + placeholder?: string; + + /** + * A function to callback when filter is updated. + */ + updateFilter: ( + filterFn: (item: string) => Partial | null, + query?: string + ) => void; + + /** + * Whether to use the fuzzy filter. + */ + useFuzzyFilter: boolean; } /** @@ -135,7 +145,7 @@ export const updateFilterFunction = ( }; }; -export const FilterBox = (props: IFilterBoxProps) => { +export const FilterBox = (props: IFilterBoxProps): JSX.Element => { const [filter, setFilter] = useState(props.initialQuery ?? ''); if (props.forceRefresh) { @@ -178,11 +188,13 @@ export const FilterBox = (props: IFilterBoxProps) => { return ( ); @@ -191,7 +203,7 @@ export const FilterBox = (props: IFilterBoxProps) => { /** * A widget which hosts a input textbox to filter on file names. */ -export const FilenameSearcher = (props: IFilterBoxProps) => { +export const FilenameSearcher = (props: IFilterBoxProps): ReactWidget => { return ReactWidget.create( { + return this.content.widgets; + } + + /** + * Add a widget to the content panel bottom. + * + * @param widget Widget to add + */ + addWidget(widget: Toolbar.IWidgetToolbar): void { + this.content.addWidget(widget); + } + + /** + * Insert a widget at the given position in the content panel. + * + * @param index Position + * @param widget Widget to insert + */ + insertWidget(index: number, widget: Toolbar.IWidgetToolbar): void { + this.content.insertWidget(index, widget); + } + + private addHeader(header?: Panel) { + const theHeader = (this._header = header || new Panel()); + theHeader.addClass('jp-SidePanel-header'); + + (this.layout as PanelLayout).insertWidget(0, theHeader); + } + + private addToolbar(toolbar?: Toolbar) { + const theToolbar = (this._toolbar = toolbar ?? new Toolbar()); + theToolbar.addClass('jp-SidePanel-toolbar'); + theToolbar.node.setAttribute('role', 'navigation'); + theToolbar.node.setAttribute( + 'aria-label', + this._trans.__('side panel actions') + ); + (this.layout as PanelLayout).insertWidget( + (this.layout as PanelLayout).widgets.length - 1, + theToolbar + ); + } + + protected _content: Panel; + protected _header: Panel; + protected _toolbar: Toolbar; + protected _trans: TranslationBundle; +} + +/** + * The namespace for the `SidePanel` class statics. + */ +export namespace SidePanel { + /** + * An options object for creating a side panel widget. + */ + export interface IOptions extends AccordionPanel.IOptions { + /** + * The main child of the side panel + * + * If nothing is provided it fallback to an AccordionToolbar panel. + */ + content?: Panel; + + /** + * The header is at the top of the SidePanel, + * and that extensions can populate. + * + * Defaults to an empty Panel if requested otherwise it won't be created. + */ + header?: Panel; + + /** + * The toolbar to use for the widget. + * It sits between the header and the content + * + * Defaults to an empty toolbar if requested otherwise it won't be created. + */ + toolbar?: Toolbar; + + /** + * The application language translator. + */ + translator?: ITranslator; + } +} diff --git a/packages/apputils/src/spinner.ts b/packages/ui-components/src/components/spinner.ts similarity index 100% rename from packages/apputils/src/spinner.ts rename to packages/ui-components/src/components/spinner.ts diff --git a/packages/apputils/src/styling.ts b/packages/ui-components/src/components/styling.ts similarity index 77% rename from packages/apputils/src/styling.ts rename to packages/ui-components/src/components/styling.ts index b0832a533475..3a3fee6e794b 100644 --- a/packages/apputils/src/styling.ts +++ b/packages/ui-components/src/components/styling.ts @@ -1,7 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { caretDownEmptyIcon } from '@jupyterlab/ui-components'; +import { caretDownEmptyIcon } from '../icon'; /** * A namespace for node styling. @@ -39,7 +39,8 @@ export namespace Styling { node.classList.add('jp-mod-styled'); } if (node.localName === 'select') { - wrapSelect(node as HTMLSelectElement); + const multiple = node.hasAttribute('multiple'); + wrapSelect(node as HTMLSelectElement, multiple); } const nodes = node.getElementsByTagName(tagName); for (let i = 0; i < nodes.length; i++) { @@ -49,7 +50,8 @@ export namespace Styling { child.classList.add(className); } if (tagName === 'select') { - wrapSelect(child as HTMLSelectElement); + const multiple = child.hasAttribute('multiple'); + wrapSelect(child as HTMLSelectElement, multiple); } } } @@ -57,7 +59,10 @@ export namespace Styling { /** * Wrap a select node. */ - export function wrapSelect(node: HTMLSelectElement): HTMLElement { + export function wrapSelect( + node: HTMLSelectElement, + multiple?: boolean + ): HTMLElement { const wrapper = document.createElement('div'); wrapper.classList.add('jp-select-wrapper'); node.addEventListener('focus', Private.onFocus); @@ -68,16 +73,20 @@ export namespace Styling { } wrapper.appendChild(node); - // add the icon node - wrapper.appendChild( - caretDownEmptyIcon.element({ - tag: 'span', - stylesheet: 'select', - right: '8px', - top: '5px', - width: '18px' - }) - ); + if (multiple) { + wrapper.classList.add('multiple'); + } else { + // add the icon node + wrapper.appendChild( + caretDownEmptyIcon.element({ + tag: 'span', + stylesheet: 'select', + right: '8px', + top: '5px', + width: '18px' + }) + ); + } return wrapper; } diff --git a/packages/ui-components/src/components/switch.ts b/packages/ui-components/src/components/switch.ts index 7829454abd1f..fefba4bc0bfc 100644 --- a/packages/ui-components/src/components/switch.ts +++ b/packages/ui-components/src/components/switch.ts @@ -33,7 +33,7 @@ export class Switch extends Widget { /** * The value of the switch. */ - get value() { + get value(): boolean { return this._value; } set value(newValue: boolean) { @@ -88,7 +88,7 @@ export class Switch extends Widget { this._button.addEventListener('click', this); } - protected onBeforeDetach() { + protected onBeforeDetach(): void { this._button.removeEventListener('click', this); } diff --git a/packages/ui-components/src/components/toolbar.tsx b/packages/ui-components/src/components/toolbar.tsx new file mode 100644 index 000000000000..cc9c954958ec --- /dev/null +++ b/packages/ui-components/src/components/toolbar.tsx @@ -0,0 +1,1375 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx +import { + ITranslator, + nullTranslator, + TranslationBundle +} from '@jupyterlab/translation'; +import { + Button, + circleEmptyIcon, + circleIcon, + classes, + ellipsesIcon, + LabIcon, + offlineBoltIcon, + refreshIcon, + stopIcon +} from '@jupyterlab/ui-components'; +import { find, IIterator, map, some } from '@lumino/algorithm'; +======== +import { ITranslator, nullTranslator } from '@jupyterlab/translation'; +import { find, map, some } from '@lumino/algorithm'; +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx +import { CommandRegistry } from '@lumino/commands'; +import { ReadonlyJSONObject } from '@lumino/coreutils'; +import { Message, MessageLoop } from '@lumino/messaging'; +import { AttachedProperty } from '@lumino/properties'; +import { Layout, PanelLayout, Widget } from '@lumino/widgets'; +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx +import * as React from 'react'; +import { ISessionContext, sessionContextDialogs } from '../sessioncontext'; +import { translateKernelStatuses } from '../kernelstatuses'; +import { ReactWidget, UseSignal } from '../vdom'; +import { Throttler } from '@lumino/polling'; +======== +import { Throttler } from '@lumino/polling'; +import * as React from 'react'; +import { Button } from './button'; +import { ellipsesIcon, LabIcon } from '../icon'; +import { classes } from '../utils'; +import { ReactWidget, UseSignal } from './vdom'; +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + +/** + * The class name added to toolbars. + */ +const TOOLBAR_CLASS = 'jp-Toolbar'; + +/** + * Toolbar pop-up opener button name + */ +const TOOLBAR_OPENER_NAME = 'toolbar-popup-opener'; + +/** + * The class name added to toolbar items. + */ +const TOOLBAR_ITEM_CLASS = 'jp-Toolbar-item'; + +/** + * Toolbar pop-up opener button name + */ +const TOOLBAR_OPENER_NAME = 'toolbar-popup-opener'; + +/** + * The class name added to toolbar spacer. + */ +const TOOLBAR_SPACER_CLASS = 'jp-Toolbar-spacer'; + +/** + * A layout for toolbars. + * + * #### Notes + * This layout automatically collapses its height if there are no visible + * toolbar widgets, and expands to the standard toolbar height if there are + * visible toolbar widgets. + */ +class ToolbarLayout extends PanelLayout { + /** + * A message handler invoked on a `'fit-request'` message. + * + * If any child widget is visible, expand the toolbar height to the normal + * toolbar height. + */ + protected onFitRequest(msg: Message): void { + super.onFitRequest(msg); + if (this.parent!.isAttached) { + // If there are any widgets not explicitly hidden, expand the toolbar to + // accommodate them. + if (some(this.widgets, w => !w.isHidden)) { + this.parent!.node.style.minHeight = 'var(--jp-private-toolbar-height)'; + this.parent!.removeClass('jp-Toolbar-micro'); + } else { + this.parent!.node.style.minHeight = ''; + this.parent!.addClass('jp-Toolbar-micro'); + } + } + + // Set the dirty flag to ensure only a single update occurs. + this._dirty = true; + + // Notify the ancestor that it should fit immediately. This may + // cause a resize of the parent, fulfilling the required update. + if (this.parent!.parent) { + MessageLoop.sendMessage(this.parent!.parent!, Widget.Msg.FitRequest); + } + + // If the dirty flag is still set, the parent was not resized. + // Trigger the required update on the parent widget immediately. + if (this._dirty) { + MessageLoop.sendMessage(this.parent!, Widget.Msg.UpdateRequest); + } + } + + /** + * A message handler invoked on an `'update-request'` message. + */ + protected onUpdateRequest(msg: Message): void { + super.onUpdateRequest(msg); + if (this.parent!.isVisible) { + this._dirty = false; + } + } + + /** + * A message handler invoked on a `'child-shown'` message. + */ + protected onChildShown(msg: Widget.ChildMessage): void { + super.onChildShown(msg); + + // Post a fit request for the parent widget. + this.parent!.fit(); + } + + /** + * A message handler invoked on a `'child-hidden'` message. + */ + protected onChildHidden(msg: Widget.ChildMessage): void { + super.onChildHidden(msg); + + // Post a fit request for the parent widget. + this.parent!.fit(); + } + + /** + * A message handler invoked on a `'before-attach'` message. + */ + protected onBeforeAttach(msg: Message): void { + super.onBeforeAttach(msg); + + // Post a fit request for the parent widget. + this.parent!.fit(); + } + + /** + * Attach a widget to the parent's DOM node. + * + * @param index - The current index of the widget in the layout. + * + * @param widget - The widget to attach to the parent. + * + * #### Notes + * This is a reimplementation of the superclass method. + */ + protected attachWidget(index: number, widget: Widget): void { + super.attachWidget(index, widget); + + // Post a fit request for the parent widget. + this.parent!.fit(); + } + + /** + * Detach a widget from the parent's DOM node. + * + * @param index - The previous index of the widget in the layout. + * + * @param widget - The widget to detach from the parent. + * + * #### Notes + * This is a reimplementation of the superclass method. + */ + protected detachWidget(index: number, widget: Widget): void { + super.detachWidget(index, widget); + + // Post a fit request for the parent widget. + this.parent!.fit(); + } + + private _dirty = false; +} + +/** + * A class which provides a toolbar widget. + */ +export class Toolbar extends Widget { + /** + * Construct a new toolbar widget. + */ + constructor(options: Toolbar.IOptions = {}) { + super(); + this.addClass(TOOLBAR_CLASS); + this.layout = options.layout ?? new ToolbarLayout(); + } + + /** + * Get an iterator over the ordered toolbar item names. + * + * @returns An iterator over the toolbar item names. + */ + names(): IterableIterator { + const layout = this.layout as ToolbarLayout; + return map(layout.widgets, widget => { + return Private.nameProperty.get(widget); + }); + } + + /** + * Add an item to the end of the toolbar. + * + * @param name - The name of the widget to add to the toolbar. + * + * @param widget - The widget to add to the toolbar. + * + * @param index - The optional name of the item to insert after. + * + * @returns Whether the item was added to toolbar. Returns false if + * an item of the same name is already in the toolbar. + * + * #### Notes + * The item can be removed from the toolbar by setting its parent to `null`. + */ + addItem(name: string, widget: T): boolean { + const layout = this.layout as ToolbarLayout; + return this.insertItem(layout.widgets.length, name, widget); + } + + /** + * Insert an item into the toolbar at the specified index. + * + * @param index - The index at which to insert the item. + * + * @param name - The name of the item. + * + * @param widget - The widget to add. + * + * @returns Whether the item was added to the toolbar. Returns false if + * an item of the same name is already in the toolbar. + * + * #### Notes + * The index will be clamped to the bounds of the items. + * The item can be removed from the toolbar by setting its parent to `null`. + */ + insertItem(index: number, name: string, widget: T): boolean { + const existing = find(this.names(), value => value === name); + if (existing) { + return false; + } + widget.addClass(TOOLBAR_ITEM_CLASS); + const layout = this.layout as ToolbarLayout; + + const j = Math.max(0, Math.min(index, layout.widgets.length)); + layout.insertWidget(j, widget); + + Private.nameProperty.set(widget, name); + return true; + } + + /** + * Insert an item into the toolbar at the after a target item. + * + * @param at - The target item to insert after. + * + * @param name - The name of the item. + * + * @param widget - The widget to add. + * + * @returns Whether the item was added to the toolbar. Returns false if + * an item of the same name is already in the toolbar. + * + * #### Notes + * The index will be clamped to the bounds of the items. + * The item can be removed from the toolbar by setting its parent to `null`. + */ + insertAfter(at: string, name: string, widget: T): boolean { + return this._insertRelative(at, 1, name, widget); + } + + /** + * Insert an item into the toolbar at the before a target item. + * + * @param at - The target item to insert before. + * + * @param name - The name of the item. + * + * @param widget - The widget to add. + * + * @returns Whether the item was added to the toolbar. Returns false if + * an item of the same name is already in the toolbar. + * + * #### Notes + * The index will be clamped to the bounds of the items. + * The item can be removed from the toolbar by setting its parent to `null`. + */ + insertBefore(at: string, name: string, widget: T): boolean { + return this._insertRelative(at, 0, name, widget); + } + + private _insertRelative( + at: string, + offset: number, + name: string, + widget: T + ): boolean { + const nameWithIndex = map(this.names(), (name, i) => { + return { name: name, index: i }; + }); + const target = find(nameWithIndex, x => x.name === at); + if (target) { + return this.insertItem(target.index + offset, name, widget); + } + return false; + } + + /** + * Handle the DOM events for the widget. + * + * @param event - The DOM event sent to the widget. + * + * #### Notes + * This method implements the DOM `EventListener` interface and is + * called in response to events on the dock panel's node. It should + * not be called directly by user code. + */ + handleEvent(event: Event): void { + switch (event.type) { + case 'click': + this.handleClick(event); + break; + default: + break; + } + } + + /** + * Handle a DOM click event. + */ + protected handleClick(event: Event): void { + // Stop propagating the click outside the toolbar + event.stopPropagation(); + + // Clicking a label focuses the corresponding control + // that is linked with `for` attribute, so let it be. + if (event.target instanceof HTMLLabelElement) { + const forId = event.target.getAttribute('for'); + if (forId && this.node.querySelector(`#${forId}`)) { + return; + } + } + + // If this click already focused a control, let it be. + if (this.node.contains(document.activeElement)) { + return; + } + + // Otherwise, activate the parent widget, which may take focus if desired. + if (this.parent) { + this.parent.activate(); + } + } + + /** + * Handle `after-attach` messages for the widget. + */ + protected onAfterAttach(msg: Message): void { + this.node.addEventListener('click', this); + } + + /** + * Handle `before-detach` messages for the widget. + */ + protected onBeforeDetach(msg: Message): void { + this.node.removeEventListener('click', this); + } +} + +/** + * A class which provides a toolbar widget. + */ +export class ReactiveToolbar extends Toolbar { + /** + * Construct a new toolbar widget. + */ + constructor() { + super(); + this.insertItem(0, TOOLBAR_OPENER_NAME, this.popupOpener); + this.popupOpener.hide(); + this._resizer = new Throttler(this._onResize.bind(this), 500); + } + + /** + * Dispose of the widget and its descendant widgets. + */ + dispose(): void { + if (this.isDisposed) { + return; + } + + if (this._resizer) { + this._resizer.dispose(); + } + + super.dispose(); + } + + /** + * Insert an item into the toolbar at the after a target item. + * + * @param at - The target item to insert after. + * + * @param name - The name of the item. + * + * @param widget - The widget to add. + * + * @returns Whether the item was added to the toolbar. Returns false if + * an item of the same name is already in the toolbar or if the target + * is the toolbar pop-up opener. + * + * #### Notes + * The index will be clamped to the bounds of the items. + * The item can be removed from the toolbar by setting its parent to `null`. + */ + insertAfter(at: string, name: string, widget: Widget): boolean { + if (at === TOOLBAR_OPENER_NAME) { + return false; + } + return super.insertAfter(at, name, widget); + } + + /** + * Insert an item into the toolbar at the specified index. + * + * @param index - The index at which to insert the item. + * + * @param name - The name of the item. + * + * @param widget - The widget to add. + * + * @returns Whether the item was added to the toolbar. Returns false if + * an item of the same name is already in the toolbar. + * + * #### Notes + * The index will be clamped to the bounds of the items. + * The item can be removed from the toolbar by setting its parent to `null`. + */ + insertItem(index: number, name: string, widget: Widget): boolean { + if (widget instanceof ToolbarPopupOpener) { + return super.insertItem(index, name, widget); + } else { + const j = Math.max( + 0, + Math.min(index, (this.layout as ToolbarLayout).widgets.length - 1) + ); + return super.insertItem(j, name, widget); + } + } + + /** + * A message handler invoked on a `'before-hide'` message. + * + * It will hide the pop-up panel + */ + onBeforeHide(msg: Message): void { + this.popupOpener.hidePopup(); + super.onBeforeHide(msg); + } + + protected onResize(msg: Widget.ResizeMessage): void { + super.onResize(msg); + if (msg.width > 0 && this._resizer) { + void this._resizer.invoke(); + } + } + + private _onResize() { + if (this.parent && this.parent.isAttached) { + const toolbarWidth = this.node.clientWidth; + const opener = this.popupOpener; + const openerWidth = 30; + const toolbarPadding = 2; + const layout = this.layout as ToolbarLayout; + + let width = opener.isHidden + ? toolbarPadding + : toolbarPadding + openerWidth; + let index = 0; + const widgetsToRemove = []; + const toIndex = layout.widgets.length - 1; + + while (index < toIndex) { + const widget = layout.widgets[index]; + this._saveWidgetWidth(widget); + width += this._getWidgetWidth(widget); + if ( + widgetsToRemove.length === 0 && + opener.isHidden && + width + openerWidth > toolbarWidth + ) { + width += openerWidth; + } + if (width > toolbarWidth) { + widgetsToRemove.push(widget); + } + index++; + } + + while (widgetsToRemove.length > 0) { + const widget = widgetsToRemove.pop() as Widget; + width -= this._getWidgetWidth(widget); + opener.addWidget(widget); + } + + if (opener.widgetCount() > 0) { + const widgetsToAdd = []; + let index = 0; + let widget = opener.widgetAt(index); + const widgetCount = opener.widgetCount(); + + width += this._getWidgetWidth(widget); + + if (widgetCount === 1 && width - openerWidth <= toolbarWidth) { + width -= openerWidth; + } + + while (width < toolbarWidth && index < widgetCount) { + widgetsToAdd.push(widget); + index++; + widget = opener.widgetAt(index); + if (widget) { + width += this._getWidgetWidth(widget); + } else { + break; + } + } + + while (widgetsToAdd.length > 0) { + const widget = widgetsToAdd.shift()!; + this.addItem(Private.nameProperty.get(widget), widget); + } + } + + if (opener.widgetCount() > 0) { + opener.updatePopup(); + opener.show(); + } else { + opener.hide(); + } + } + } + + private _saveWidgetWidth(widget: Widget) { + const widgetName = Private.nameProperty.get(widget); + this._widgetWidths![widgetName] = widget.hasClass(TOOLBAR_SPACER_CLASS) + ? 2 + : widget.node.clientWidth; + } + + private _getWidgetWidth(widget: Widget): number { + const widgetName = Private.nameProperty.get(widget); + return this._widgetWidths![widgetName]; + } + + protected readonly popupOpener: ToolbarPopupOpener = new ToolbarPopupOpener(); + private readonly _widgetWidths: { [key: string]: number } = {}; + private readonly _resizer: Throttler; +} + +/** + * The namespace for Toolbar class statics. + */ +export namespace Toolbar { + /** + * The options used to create a toolbar. +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + */ + export interface IOptions { + /** + * Toolbar widget layout. + */ + layout?: Layout; + } + + /** + * Widget with associated toolbar + */ + export interface IWidgetToolbar extends Widget { + /** + * Toolbar of actions on the widget + */ + toolbar?: Toolbar; + } + + /** + * Create an interrupt toolbar item. + * + * @deprecated since version v3.2 + * This is dead code now. +======== +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + */ + export interface IOptions { + /** + * Toolbar widget layout. + */ + layout?: Layout; + } + + /** +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + * Create a restart toolbar item. + * + * @deprecated since v3.2 + * This is dead code now. +======== + * Widget with associated toolbar +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + */ + export interface IWidgetToolbar extends Widget { + /** + * Toolbar of actions on the widget + */ + toolbar?: Toolbar; + } + + /** + * Create a toolbar spacer item. + * + * #### Notes + * It is a flex spacer that separates the left toolbar items + * from the right toolbar items. + */ + export function createSpacerItem(): Widget { + return new Private.Spacer(); + } +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + + /** + * Create a kernel name indicator item. + * + * #### Notes + * It will display the `'display_name`' of the session context. It can + * handle a change in context or kernel. + */ + export function createKernelNameItem( + sessionContext: ISessionContext, + dialogs?: ISessionContext.IDialogs, + translator?: ITranslator + ): Widget { + const el = ReactWidget.create( + + ); + el.addClass('jp-KernelName'); + return el; + } + + /** + * Create a kernel status indicator item. + * + * @deprecated since v3.5 + * The kernel status indicator is now replaced by the execution status indicator. + * + * #### Notes + * It will show a busy status if the kernel status is busy. + * It will show the current status in the node title. + * It can handle a change to the context or the kernel. + */ + export function createKernelStatusItem( + sessionContext: ISessionContext, + translator?: ITranslator + ): Widget { + return new Private.KernelStatus(sessionContext, translator); + } +======== +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx +} + +/** + * Namespace for ToolbarButtonComponent. + */ +export namespace ToolbarButtonComponent { + /** + * Interface for ToolbarButtonComponent props. + */ + export interface IProps { + className?: string; + /** + * Data set of the button + */ + dataset?: DOMStringMap; + label?: string; + icon?: LabIcon.IMaybeResolvable; + iconClass?: string; + iconLabel?: string; + tooltip?: string; + onClick?: () => void; + enabled?: boolean; + pressed?: boolean; + pressedIcon?: LabIcon.IMaybeResolvable; + pressedTooltip?: string; + disabledTooltip?: string; + + /** + * Trigger the button on the actual onClick event rather than onMouseDown. + * + * See note in ToolbarButtonComponent below as to why the default is to + * trigger on onMouseDown. + */ + actualOnClick?: boolean; + + /** + * The application language translator. + */ + translator?: ITranslator; + } +} + +/** + * React component for a toolbar button. + * + * @param props - The props for ToolbarButtonComponent. + */ +export function ToolbarButtonComponent( + props: ToolbarButtonComponent.IProps +): JSX.Element { + // In some browsers, a button click event moves the focus from the main + // content to the button (see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus). + // We avoid a click event by calling preventDefault in mousedown, and + // we bind the button action to `mousedown`. + const handleMouseDown = (event: React.MouseEvent) => { + // Fire action only when left button is pressed. + if (event.button === 0) { + event.preventDefault(); + props.onClick?.(); + } + }; + + const handleKeyDown = (event: React.KeyboardEvent) => { + const { key } = event; + if (key === 'Enter' || key === ' ') { + props.onClick?.(); + } + }; + + const handleClick = (event: React.MouseEvent) => { + if (event.button === 0) { + props.onClick?.(); + } + }; + + const getTooltip = () => { + if (props.enabled === false && props.disabledTooltip) { + return props.disabledTooltip; + } else if (props.pressed && props.pressedTooltip) { + return props.pressedTooltip; + } else { + return props.tooltip || props.iconLabel; + } + }; + + return ( + + ); +} + +/** + * Adds the toolbar button class to the toolbar widget. + * @param w Toolbar button widget. + */ +export function addToolbarButtonClass(w: T): T { + w.addClass('jp-ToolbarButton'); + return w; +} + +/** + * Lumino Widget version of static ToolbarButtonComponent. + */ +export class ToolbarButton extends ReactWidget { + /** + * Creates a toolbar button + * @param props props for underlying `ToolbarButton` component + */ + constructor(private props: ToolbarButtonComponent.IProps = {}) { + super(); + addToolbarButtonClass(this); + this._enabled = props.enabled ?? true; + this._pressed = this._enabled! && (props.pressed ?? false); + this._onClick = props.onClick!; + } + + /** + * Sets the pressed state for the button + * @param value true if button is pressed, false otherwise + */ + set pressed(value: boolean) { + if (this.enabled && value !== this._pressed) { + this._pressed = value; + this.update(); + } + } + + /** + * Returns true if button is pressed, false otherwise + */ + get pressed(): boolean { + return this._pressed!; + } + + /** + * Sets the enabled state for the button + * @param value true to enable the button, false otherwise + */ + set enabled(value: boolean) { + if (value != this._enabled) { + this._enabled = value; + if (!this._enabled) { + this._pressed = false; + } + this.update(); + } + } + + /** + * Returns true if button is enabled, false otherwise + */ + get enabled(): boolean { + return this._enabled; + } + + /** + * Sets the click handler for the button + * @param value click handler + */ + set onClick(value: () => void) { + if (value !== this._onClick) { + this._onClick = value; + this.update(); + } + } + + /** + * Returns the click handler for the button + */ +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + get onClick() { +======== + get onClick(): () => void { +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + return this._onClick!; + } + + render(): JSX.Element { + return ( + + ); + } + + private _pressed: boolean; + private _enabled: boolean; + private _onClick: () => void; +} + +/** + * Namespace for CommandToolbarButtonComponent. + */ +export namespace CommandToolbarButtonComponent { + /** + * Interface for CommandToolbarButtonComponent props. + */ + export interface IProps { + /** + * Application commands registry + */ + commands: CommandRegistry; + /** + * Command unique id + */ + id: string; + /** + * Command arguments + */ + args?: ReadonlyJSONObject; + /** + * Overrides command icon + */ + icon?: LabIcon; + /** + * Overrides command label + */ + label?: string; +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx +======== + /** + * Overrides command caption + */ + caption?: string; +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + } +} + +/** + * React component for a toolbar button that wraps a command. + * + * This wraps the ToolbarButtonComponent and watches the command registry + * for changes to the command. + */ +export function CommandToolbarButtonComponent( + props: CommandToolbarButtonComponent.IProps +): JSX.Element { + return ( + + (args.id === props.id && args.type === 'changed') || + args.type === 'many-changed' + } + > + {() => } + + ); +} + +/* + * Adds the command toolbar button class to the command toolbar widget. + * @param w Command toolbar button widget. + */ +export function addCommandToolbarButtonClass(w: Widget): Widget { + w.addClass('jp-CommandToolbarButton'); + return w; +} + +/** + * Phosphor Widget version of CommandToolbarButtonComponent. + */ +export class CommandToolbarButton extends ReactWidget { + /** + * Creates a command toolbar button + * @param props props for underlying `CommandToolbarButtonComponent` component + */ + constructor(private props: CommandToolbarButtonComponent.IProps) { + super(); + addCommandToolbarButtonClass(this); + } + render(): JSX.Element { + return ; + } +} + +/** + * A class which provides a toolbar popup + * used to store widgets that don't fit + * in the toolbar when it is resized + */ +class ToolbarPopup extends Widget { + width: number = 0; + + /** + * Construct a new ToolbarPopup + */ + constructor() { + super(); + this.addClass('jp-Toolbar-responsive-popup'); + this.layout = new PanelLayout(); + Widget.attach(this, document.body); + this.hide(); + } + + /** + * Updates the width of the popup, this + * should match with the toolbar width + * + * @param width - The width to resize to + * @protected + */ + updateWidth(width: number) { + if (width > 0) { + this.width = width; + this.node.style.width = `${width}px`; + } + } + + /** + * Aligns the popup to left bottom of widget + * + * @param widget the widget to align to + * @private + */ + alignTo(widget: Widget) { + const { + height: widgetHeight, + width: widgetWidth, + x: widgetX, + y: widgetY + } = widget.node.getBoundingClientRect(); + const width = this.width; + this.node.style.left = `${widgetX + widgetWidth - width + 1}px`; + this.node.style.top = `${widgetY + widgetHeight + 1}px`; + } + + /** + * Inserts the widget at specified index + * @param index the index + * @param widget widget to add + */ + insertWidget(index: number, widget: Widget) { + (this.layout as PanelLayout).insertWidget(0, widget); + } + + /** + * Total number of widgets in the popup + */ + widgetCount() { + return (this.layout as PanelLayout).widgets.length; + } + + /** + * Returns the widget at index + * @param index the index + */ + widgetAt(index: number) { + return (this.layout as PanelLayout).widgets[index]; + } +} + +/** + * A class that provides a ToolbarPopupOpener, + * which is a button added to toolbar when + * the toolbar items overflow toolbar width + */ +class ToolbarPopupOpener extends ToolbarButton { + /** + * Create a new popup opener + */ +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + constructor() { +======== + constructor(props: ToolbarButtonComponent.IProps = {}) { + const trans = (props.translator || nullTranslator).load('jupyterlab'); +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + super({ + icon: ellipsesIcon, + onClick: () => { + this.handleClick(); +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + } + }); + this.addClass('jp-Toolbar-responsive-opener'); +======== + }, + tooltip: trans.__('More commands') + }); + this.addClass('jp-Toolbar-responsive-opener'); + +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + this.popup = new ToolbarPopup(); + } + + /** + * Add widget to the popup, prepends widgets + * @param widget the widget to add + */ + addWidget(widget: Widget) { + this.popup.insertWidget(0, widget); + } + + /** + * Dispose of the widget and its descendant widgets. + * + * #### Notes + * It is unsafe to use the widget after it has been disposed. + * + * All calls made to this method after the first are a no-op. + */ + dispose(): void { + if (this.isDisposed) { + return; + } + this.popup.dispose(); + super.dispose(); + } + + /** + * Hides the opener and the popup + */ + hide(): void { + super.hide(); + this.hidePopup(); + } + + /** + * Hides the popup + */ + hidePopup(): void { + this.popup.hide(); + } + + /** + * Updates width and position of the popup + * to align with the toolbar + */ + updatePopup(): void { + this.popup.updateWidth(this.parent!.node.clientWidth); + this.popup.alignTo(this.parent!); + } + + /** + * Returns widget at index in the popup + * @param index + */ + widgetAt(index: number) { + return this.popup.widgetAt(index); + } + + /** + * Returns total number of widgets in the popup + * + * @returns Number of widgets + */ + widgetCount(): number { + return this.popup.widgetCount(); + } + + protected handleClick() { + this.updatePopup(); + this.popup.setHidden(!this.popup.isHidden); + } + + protected popup: ToolbarPopup; +} + +/** + * A namespace for private data. + */ +namespace Private { + export function propsFromCommand( + options: CommandToolbarButtonComponent.IProps + ): ToolbarButtonComponent.IProps { + const { commands, id, args } = options; + + const iconClass = commands.iconClass(id, args); + const iconLabel = commands.iconLabel(id, args); +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + // DEPRECATED: remove _icon when lumino 2.0 is adopted + // if icon is aliasing iconClass, don't use it + const _icon = options.icon ?? commands.icon(id, args); + const icon = _icon === iconClass ? undefined : _icon; +======== + const icon = options.icon ?? commands.icon(id, args); +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + + const label = commands.label(id, args); + let className = commands.className(id, args); + // Add the boolean state classes. + if (commands.isToggled(id, args)) { + className += ' lm-mod-toggled'; + } + if (!commands.isVisible(id, args)) { + className += ' lm-mod-hidden'; + } + + let tooltip = + commands.caption(id, args) || options.label || label || iconLabel; + // Shows hot keys in tooltips + const binding = commands.keyBindings.find(b => b.command === id); + if (binding) { + const ks = binding.keys.map(CommandRegistry.formatKeystroke).join(', '); + tooltip = `${tooltip} (${ks})`; + } + const onClick = () => { + void commands.execute(id, args); + }; + const enabled = commands.isEnabled(id, args); + + return { + className, + dataset: { 'data-command': options.id }, + icon, + iconClass, +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + tooltip, +======== + tooltip: options.caption ?? tooltip, +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx + onClick, + enabled, + label: options.label ?? label + }; + } + + /** + * An attached property for the name of a toolbar item. + */ + export const nameProperty = new AttachedProperty({ + name: 'name', + create: () => '' + }); + + /** + * A spacer widget. + */ + export class Spacer extends Widget { + /** + * Construct a new spacer widget. + */ + constructor() { + super(); + this.addClass(TOOLBAR_SPACER_CLASS); + } + } +<<<<<<<< HEAD:packages/apputils/src/toolbar/widget.tsx + + /** + * Namespace for KernelNameComponent. + */ + export namespace KernelNameComponent { + /** + * Interface for KernelNameComponent props. + */ + export interface IProps { + sessionContext: ISessionContext; + dialogs: ISessionContext.IDialogs; + translator?: ITranslator; + } + } + + /** + * React component for a kernel name button. + * + * This wraps the ToolbarButtonComponent and watches the kernel + * session for changes. + */ + + export function KernelNameComponent(props: KernelNameComponent.IProps) { + const translator = props.translator || nullTranslator; + const trans = translator.load('jupyterlab'); + const callback = () => { + void props.dialogs.selectKernel(props.sessionContext, translator); + }; + return ( + + {sessionContext => ( + + )} + + ); + } + + /** + * A toolbar item that displays kernel status. + */ + export class KernelStatus extends Widget { + /** + * Construct a new kernel status widget. + */ + constructor(sessionContext: ISessionContext, translator?: ITranslator) { + super(); + this.translator = translator || nullTranslator; + this._trans = this.translator.load('jupyterlab'); + this.addClass(TOOLBAR_KERNEL_STATUS_CLASS); + this._statusNames = translateKernelStatuses(this.translator); + this._onStatusChanged(sessionContext); + sessionContext.statusChanged.connect(this._onStatusChanged, this); + sessionContext.connectionStatusChanged.connect( + this._onStatusChanged, + this + ); + } + + /** + * Handle a status on a kernel. + */ + private _onStatusChanged(sessionContext: ISessionContext) { + if (this.isDisposed) { + return; + } + + const status = sessionContext.kernelDisplayStatus; + const circleIconProps: LabIcon.IProps = { + container: this.node, + title: this._trans.__('Kernel %1', this._statusNames[status] || status), + stylesheet: 'toolbarButton', + alignSelf: 'normal', + height: '24px' + }; + + // set the icon + LabIcon.remove(this.node); + if ( + status === 'busy' || + status === 'starting' || + status === 'terminating' || + status === 'restarting' || + status === 'initializing' + ) { + circleIcon.element(circleIconProps); + } else if ( + status === 'connecting' || + status === 'disconnected' || + status === 'unknown' + ) { + offlineBoltIcon.element(circleIconProps); + } else { + circleEmptyIcon.element(circleIconProps); + } + } + + protected translator: ITranslator; + private _trans: TranslationBundle; + private readonly _statusNames: Record< + ISessionContext.KernelDisplayStatus, + string + >; + } +======== +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/src/components/toolbar.tsx +} diff --git a/packages/apputils/src/vdom.ts b/packages/ui-components/src/components/vdom.ts similarity index 83% rename from packages/apputils/src/vdom.ts rename to packages/ui-components/src/components/vdom.ts index ad945d4082cb..559bbfb848d9 100644 --- a/packages/apputils/src/vdom.ts +++ b/packages/ui-components/src/components/vdom.ts @@ -6,16 +6,19 @@ import { Message, MessageLoop } from '@lumino/messaging'; import { ISignal, Signal } from '@lumino/signaling'; import { Widget } from '@lumino/widgets'; import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import { createRoot, Root } from 'react-dom/client'; type ReactRenderElement = | Array> | React.ReactElement; /** - * An abstract class for a Phosphor widget which renders a React component. + * An abstract class for a Lumino widget which renders a React component. */ export abstract class ReactWidget extends Widget { + constructor() { + super(); + } /** * Creates a new `ReactWidget` that renders a constant element. * @param element React element to render. @@ -61,7 +64,10 @@ export abstract class ReactWidget extends Widget { */ protected onBeforeDetach(msg: Message): void { // Unmount the component so it can tear down. - ReactDOM.unmountComponentAtNode(this.node); + if (this._rootDOM !== null) { + this._rootDOM.unmount(); + this._rootDOM = null; + } } /** @@ -72,18 +78,33 @@ export abstract class ReactWidget extends Widget { private renderDOM(): Promise { return new Promise(resolve => { const vnode = this.render(); + if (this._rootDOM === null) { + this._rootDOM = createRoot(this.node); + } // Split up the array/element cases so type inference chooses the right // signature. if (Array.isArray(vnode)) { - ReactDOM.render(vnode, this.node, resolve); + this._rootDOM.render(vnode); + // Resolves after the widget has been rendered. + // https://github.com/reactwg/react-18/discussions/5#discussioncomment-798304 + requestIdleCallback(() => resolve()); } else if (vnode) { - ReactDOM.render(vnode, this.node, resolve); + this._rootDOM.render(vnode); + // Resolves after the widget has been rendered. + // https://github.com/reactwg/react-18/discussions/5#discussioncomment-798304 + requestIdleCallback(() => resolve()); + } else { + // If the virtual node is null, unmount the node content + this._rootDOM.unmount(); + this._rootDOM = null; + requestIdleCallback(() => resolve()); } }); } // Set whenever a new render is triggered and resolved when it is finished. renderPromise?: Promise; + private _rootDOM: Root | null = null; } /** @@ -95,9 +116,9 @@ export abstract class VDomRenderer< /** * Create a new VDomRenderer */ - constructor(model: T extends null ? void : T) { + constructor(model?: T) { super(); - this.model = ((model ?? null) as unknown) as T; + this.model = (model ?? null) as unknown as T; } /** * A signal emitted when the model changes. @@ -135,7 +156,7 @@ export abstract class VDomRenderer< /** * Dispose this widget. */ - dispose() { + dispose(): void { if (this.isDisposed) { return; } @@ -192,7 +213,7 @@ export interface IUseSignalState { } /** - * UseSignal provides a way to hook up a Phosphor signal to a React element, + * UseSignal provides a way to hook up a Lumino signal to a React element, * so that the element is re-rendered every time the signal fires. * * It is implemented through the "render props" technique, using the `children` @@ -206,7 +227,7 @@ export interface IUseSignalState { * ``` * function LiveButton(isActiveSignal: ISignal) { * return ( - * + * * {(_, isActive) => -); - -export const emoji = () => ( - -); diff --git a/packages/ui-components/stories/labicon-sizes.stories.tsx b/packages/ui-components/stories/labicon-sizes.stories.tsx deleted file mode 100644 index f7bba43bdbd1..000000000000 --- a/packages/ui-components/stories/labicon-sizes.stories.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Example story for styling an icon's size. - */ -// need this to avoid -// TS2686: 'React' refers to a UMD global, but the current file is a module. -import '@jupyterlab/application/style/index.css'; -import '@jupyterlab/theme-light-extension/style/index.css'; -import React from 'react'; -import { clearIcon } from '../src'; - -export default { - // component: LabIcon, - title: 'LabIcon sizing' -}; - -export const clearSmall = () => ; -export const clearNormal = () => ; -export const clearLarge = () => ; -export const clearXlarge = () => ; diff --git a/packages/ui-components/stories/labicon.stories.tsx b/packages/ui-components/stories/labicon.stories.tsx deleted file mode 100644 index 534cad4b1d3d..000000000000 --- a/packages/ui-components/stories/labicon.stories.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Example story for styling an icon. - */ -// need this to avoid -// TS2686: 'React' refers to a UMD global, but the current file is a module. -import '@jupyterlab/application/style/index.css'; -import '@jupyterlab/theme-light-extension/style/index.css'; -import React from 'react'; -import { buildIcon, html5Icon, runningIcon } from '../src'; - -export default { - // component: LabIcon, - title: 'LabIcon' -}; - -export const build = () => ; - -export const running = () => ; - -export const html5 = () => ( -
    - -
    -); diff --git a/packages/ui-components/style/base.css b/packages/ui-components/style/base.css index eca308a5f227..18d5699b8aba 100644 --- a/packages/ui-components/style/base.css +++ b/packages/ui-components/style/base.css @@ -4,110 +4,149 @@ |----------------------------------------------------------------------------*/ /* Sibling imports */ +@import './collapse.css'; @import './deprecated.css'; @import './deprecatedExtra.css'; @import './tabbar.css'; @import './icons.css'; @import './iconsalt.css'; @import './iconshover.css'; +@import './iframe.css'; +@import './hoverbox.css'; +@import './rjsfTemplates.css'; +@import './sidepanel.css'; +@import './spinner.css'; +@import './styling.css'; @import './switch.css'; - -/* Override Blueprint's _reset.scss styles */ -html { - box-sizing: unset; -} - -*, -*::before, -*::after { - box-sizing: unset; -} +@import './toolbar.css'; +@import './windowedlist.css'; body { - color: unset; - font-family: var(--jp-ui-font-family); -} - -p { - margin-top: unset; - margin-bottom: unset; -} - -small { - font-size: unset; -} - -strong { - font-weight: unset; + color: var(--jp-ui-font-color1); + font-size: var(--jp-ui-font-size1); } -/* Override Blueprint's _typography.scss styles */ +/* Disable native link decoration styles everywhere outside of dialog boxes */ a { text-decoration: unset; color: unset; } + a:hover { text-decoration: unset; color: unset; } -/* Override Blueprint's _accessibility.scss styles */ -:focus { - outline: unset; - outline-offset: unset; - -moz-outline-radius: unset; +/* Accessibility for links inside dialog box text */ +.jp-Dialog-content a { + text-decoration: revert; + color: var(--jp-content-link-color); +} + +.jp-Dialog-content a:hover { + text-decoration: revert; } /* Styles for ui-components */ .jp-Button { + color: var(--jp-ui-font-color2); border-radius: var(--jp-border-radius); - padding: 0px 12px; + padding: 0 12px; font-size: var(--jp-ui-font-size1); + + /* Copy from blueprint 3 */ + display: inline-flex; + flex-direction: row; + border: none; + cursor: pointer; + align-items: center; + justify-content: center; + text-align: left; + vertical-align: middle; + min-height: 30px; + min-width: 30px; +} + +.jp-Button:disabled { + cursor: not-allowed; +} + +.jp-Button:empty { + padding: 0 !important; +} + +.jp-Button.jp-mod-small { + min-height: 24px; + min-width: 24px; + font-size: 12px; + padding: 0 7px; } /* Use our own theme for hover styles */ -button.jp-Button.bp3-button.bp3-minimal:hover { +.jp-Button.jp-mod-minimal:hover { background-color: var(--jp-layout-color2); } -.jp-Button.minimal { - color: unset !important; + +.jp-Button.jp-mod-minimal { + background: none; } -.jp-Button.jp-ToolbarButtonComponent { - text-transform: none; +.jp-InputGroup { + display: block; + position: relative; } .jp-InputGroup input { box-sizing: border-box; + border: none; border-radius: 0; background-color: transparent; color: var(--jp-ui-font-color0); box-shadow: inset 0 0 0 var(--jp-border-width) var(--jp-input-border-color); + padding-bottom: 0; + padding-top: 0; + padding-left: 10px; + padding-right: 28px; + position: relative; + width: 100%; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + font-size: 14px; + font-weight: 400; + height: 30px; + line-height: 30px; + outline: none; + vertical-align: middle; } .jp-InputGroup input:focus { - box-shadow: inset 0 0 0 var(--jp-border-width) - var(--jp-input-active-box-shadow-color), + box-shadow: + inset 0 0 0 var(--jp-border-width) var(--jp-input-active-box-shadow-color), inset 0 0 0 3px var(--jp-input-active-box-shadow-color); } -.jp-InputGroup input::placeholder, -input::placeholder { - color: var(--jp-ui-font-color3); +.jp-InputGroup input:disabled { + cursor: not-allowed; + resize: block; + background-color: var(--jp-layout-color2); + color: var(--jp-ui-font-color2); } -.jp-BPIcon { - display: inline-block; - vertical-align: middle; - margin: auto; +.jp-InputGroup input:disabled ~ span { + cursor: not-allowed; + color: var(--jp-ui-font-color2); } -/* Stop blueprint futzing with our icon fills */ -.bp3-icon.jp-BPIcon > svg:not([fill]) { - fill: var(--jp-inverse-layout-color3); +.jp-InputGroup input::placeholder, +input::placeholder { + color: var(--jp-ui-font-color2); } .jp-InputGroupAction { + position: absolute; + bottom: 1px; + right: 0; padding: 6px; } @@ -119,6 +158,7 @@ input::placeholder { color: var(--jp-ui-font-color0); display: block; font-size: var(--jp-ui-font-size1); + font-family: var(--jp-ui-font-family); height: 24px; line-height: 14px; padding: 0 25px 0 10px; @@ -127,12 +167,25 @@ input::placeholder { -webkit-appearance: none; } +.jp-HTMLSelect.jp-DefaultStyle select:disabled { + background-color: var(--jp-layout-color2); + color: var(--jp-ui-font-color2); + cursor: not-allowed; + resize: block; +} + +.jp-HTMLSelect.jp-DefaultStyle select:disabled ~ span { + cursor: not-allowed; +} + /* Use our own theme for hover and option styles */ +/* stylelint-disable-next-line selector-max-type */ .jp-HTMLSelect.jp-DefaultStyle select:hover, .jp-HTMLSelect.jp-DefaultStyle select > option { background-color: var(--jp-layout-color2); color: var(--jp-ui-font-color0); } + select { box-sizing: border-box; } diff --git a/packages/apputils/style/collapse.css b/packages/ui-components/style/collapse.css similarity index 57% rename from packages/apputils/style/collapse.css rename to packages/ui-components/style/collapse.css index 0a1d9ed8b41d..459421bed57c 100644 --- a/packages/apputils/style/collapse.css +++ b/packages/ui-components/style/collapse.css @@ -7,23 +7,37 @@ display: flex; flex-direction: column; align-items: stretch; - border-top: 1px solid var(--jp-border-color2); - border-bottom: 1px solid var(--jp-border-color2); } .jp-Collapse-header { padding: 1px 12px; - color: var(--jp-ui-font-color1); background-color: var(--jp-layout-color1); - font-size: var(--jp-ui-font-size2); + border-bottom: solid var(--jp-border-width) var(--jp-border-color2); + color: var(--jp-ui-font-color1); + cursor: pointer; + display: flex; + align-items: center; + font-size: var(--jp-ui-font-size0); + font-weight: 600; + text-transform: uppercase; + user-select: none; +} + +.jp-Collapser-icon { + height: 16px; +} + +.jp-Collapse-header-collapsed .jp-Collapser-icon { + transform: rotate(-90deg); + margin: auto 0; } -.jp-Collapse-header:hover { - background-color: var(--jp-layout-color2); +.jp-Collapser-title { + line-height: 25px; } .jp-Collapse-contents { - padding: 0px 12px 0px 12px; + padding: 0 12px; background-color: var(--jp-layout-color1); color: var(--jp-ui-font-color1); overflow: auto; diff --git a/packages/ui-components/style/deprecated.css b/packages/ui-components/style/deprecated.css index 3bd6c6d60ba1..93633780cf2c 100644 --- a/packages/ui-components/style/deprecated.css +++ b/packages/ui-components/style/deprecated.css @@ -32,7 +32,9 @@ --jp-icon-circle: url('icons/toolbar/circle.svg'); --jp-icon-clear: url('icons/toolbar/clear.svg'); --jp-icon-close: url('icons/toolbar/close.svg'); + --jp-icon-code-check: url('icons/lsp/code-check.svg'); --jp-icon-code: url('icons/toolbar/code.svg'); + --jp-icon-collapse-all: url('icons/toolbar/collapse-all.svg'); --jp-icon-console: url('icons/filetype/console.svg'); --jp-icon-copy: url('icons/toolbar/copy.svg'); --jp-icon-copyright: url('icons/licenses/copyright.svg'); @@ -42,16 +44,21 @@ --jp-icon-duplicate: url('icons/toolbar/duplicate.svg'); --jp-icon-edit: url('icons/toolbar/edit.svg'); --jp-icon-ellipses: url('icons/toolbar/ellipses.svg'); + --jp-icon-error: url('icons/error.svg'); + --jp-icon-expand-all: url('icons/toolbar/expand-all.svg'); --jp-icon-extension: url('icons/sidebar/extension.svg'); --jp-icon-fast-forward: url('icons/toolbar/fast-forward.svg'); --jp-icon-file-upload: url('icons/toolbar/file-upload.svg'); --jp-icon-file: url('icons/filetype/file.svg'); + --jp-icon-filter-dot: url('icons/search/filter-dot.svg'); --jp-icon-filter-list: url('icons/toolbar/filter-list.svg'); + --jp-icon-filter: url('icons/search/filter.svg'); --jp-icon-folder-favorite: url('icons/filetype/folder-favorite.svg'); --jp-icon-folder: url('icons/filetype/folder.svg'); --jp-icon-home: url('icons/filetype/home.svg'); --jp-icon-html5: url('icons/filetype/html5.svg'); --jp-icon-image: url('icons/filetype/image.svg'); + --jp-icon-info: url('icons/info.svg'); --jp-icon-inspector: url('icons/filetype/inspector.svg'); --jp-icon-json: url('icons/filetype/json.svg'); --jp-icon-julia: url('icons/filetype/julia.svg'); @@ -65,7 +72,6 @@ --jp-icon-line-form: url('icons/statusbar/line-form.svg'); --jp-icon-link: url('icons/toolbar/link.svg'); --jp-icon-list: url('icons/statusbar/list.svg'); - --jp-icon-listings-info: url('icons/listings/listings-info.svg'); --jp-icon-markdown: url('icons/filetype/markdown.svg'); --jp-icon-move-down: url('icons/toolbar/move-down.svg'); --jp-icon-move-up: url('icons/toolbar/move-up.svg'); @@ -103,6 +109,7 @@ --jp-icon-user: url('icons/sidebar/user.svg'); --jp-icon-users: url('icons/sidebar/users.svg'); --jp-icon-vega: url('icons/filetype/vega.svg'); + --jp-icon-word: url('icons/search/word.svg'); --jp-icon-yaml: url('icons/filetype/yaml.svg'); } @@ -111,276 +118,395 @@ .jp-AddAboveIcon { background-image: var(--jp-icon-add-above); } + .jp-AddBelowIcon { background-image: var(--jp-icon-add-below); } + .jp-AddIcon { background-image: var(--jp-icon-add); } + .jp-BellIcon { background-image: var(--jp-icon-bell); } + .jp-BugDotIcon { background-image: var(--jp-icon-bug-dot); } + .jp-BugIcon { background-image: var(--jp-icon-bug); } + .jp-BuildIcon { background-image: var(--jp-icon-build); } + .jp-CaretDownEmptyIcon { background-image: var(--jp-icon-caret-down-empty); } + .jp-CaretDownEmptyThinIcon { background-image: var(--jp-icon-caret-down-empty-thin); } + .jp-CaretDownIcon { background-image: var(--jp-icon-caret-down); } + .jp-CaretLeftIcon { background-image: var(--jp-icon-caret-left); } + .jp-CaretRightIcon { background-image: var(--jp-icon-caret-right); } + .jp-CaretUpEmptyThinIcon { background-image: var(--jp-icon-caret-up-empty-thin); } + .jp-CaretUpIcon { background-image: var(--jp-icon-caret-up); } + .jp-CaseSensitiveIcon { background-image: var(--jp-icon-case-sensitive); } + .jp-CheckIcon { background-image: var(--jp-icon-check); } + .jp-CircleEmptyIcon { background-image: var(--jp-icon-circle-empty); } + .jp-CircleIcon { background-image: var(--jp-icon-circle); } + .jp-ClearIcon { background-image: var(--jp-icon-clear); } + .jp-CloseIcon { background-image: var(--jp-icon-close); } + +.jp-CodeCheckIcon { + background-image: var(--jp-icon-code-check); +} + .jp-CodeIcon { background-image: var(--jp-icon-code); } + +.jp-CollapseAllIcon { + background-image: var(--jp-icon-collapse-all); +} + .jp-ConsoleIcon { background-image: var(--jp-icon-console); } + .jp-CopyIcon { background-image: var(--jp-icon-copy); } + .jp-CopyrightIcon { background-image: var(--jp-icon-copyright); } + .jp-CutIcon { background-image: var(--jp-icon-cut); } + .jp-DeleteIcon { background-image: var(--jp-icon-delete); } + .jp-DownloadIcon { background-image: var(--jp-icon-download); } + .jp-DuplicateIcon { background-image: var(--jp-icon-duplicate); } + .jp-EditIcon { background-image: var(--jp-icon-edit); } + .jp-EllipsesIcon { background-image: var(--jp-icon-ellipses); } + +.jp-ErrorIcon { + background-image: var(--jp-icon-error); +} + +.jp-ExpandAllIcon { + background-image: var(--jp-icon-expand-all); +} + .jp-ExtensionIcon { background-image: var(--jp-icon-extension); } + .jp-FastForwardIcon { background-image: var(--jp-icon-fast-forward); } + .jp-FileIcon { background-image: var(--jp-icon-file); } + .jp-FileUploadIcon { background-image: var(--jp-icon-file-upload); } + +.jp-FilterDotIcon { + background-image: var(--jp-icon-filter-dot); +} + +.jp-FilterIcon { + background-image: var(--jp-icon-filter); +} + .jp-FilterListIcon { background-image: var(--jp-icon-filter-list); } + .jp-FolderFavoriteIcon { background-image: var(--jp-icon-folder-favorite); } + .jp-FolderIcon { background-image: var(--jp-icon-folder); } + .jp-HomeIcon { background-image: var(--jp-icon-home); } + .jp-Html5Icon { background-image: var(--jp-icon-html5); } + .jp-ImageIcon { background-image: var(--jp-icon-image); } + +.jp-InfoIcon { + background-image: var(--jp-icon-info); +} + .jp-InspectorIcon { background-image: var(--jp-icon-inspector); } + .jp-JsonIcon { background-image: var(--jp-icon-json); } + .jp-JuliaIcon { background-image: var(--jp-icon-julia); } + .jp-JupyterFaviconIcon { background-image: var(--jp-icon-jupyter-favicon); } + .jp-JupyterIcon { background-image: var(--jp-icon-jupyter); } + .jp-JupyterlabWordmarkIcon { background-image: var(--jp-icon-jupyterlab-wordmark); } + .jp-KernelIcon { background-image: var(--jp-icon-kernel); } + .jp-KeyboardIcon { background-image: var(--jp-icon-keyboard); } + .jp-LaunchIcon { background-image: var(--jp-icon-launch); } + .jp-LauncherIcon { background-image: var(--jp-icon-launcher); } + .jp-LineFormIcon { background-image: var(--jp-icon-line-form); } + .jp-LinkIcon { background-image: var(--jp-icon-link); } + .jp-ListIcon { background-image: var(--jp-icon-list); } -.jp-ListingsInfoIcon { - background-image: var(--jp-icon-listings-info); -} + .jp-MarkdownIcon { background-image: var(--jp-icon-markdown); } + .jp-MoveDownIcon { background-image: var(--jp-icon-move-down); } + .jp-MoveUpIcon { background-image: var(--jp-icon-move-up); } + .jp-NewFolderIcon { background-image: var(--jp-icon-new-folder); } + .jp-NotTrustedIcon { background-image: var(--jp-icon-not-trusted); } + .jp-NotebookIcon { background-image: var(--jp-icon-notebook); } + .jp-NumberingIcon { background-image: var(--jp-icon-numbering); } + .jp-OfflineBoltIcon { background-image: var(--jp-icon-offline-bolt); } + .jp-PaletteIcon { background-image: var(--jp-icon-palette); } + .jp-PasteIcon { background-image: var(--jp-icon-paste); } + .jp-PdfIcon { background-image: var(--jp-icon-pdf); } + .jp-PythonIcon { background-image: var(--jp-icon-python); } + .jp-RKernelIcon { background-image: var(--jp-icon-r-kernel); } + .jp-ReactIcon { background-image: var(--jp-icon-react); } + .jp-RedoIcon { background-image: var(--jp-icon-redo); } + .jp-RefreshIcon { background-image: var(--jp-icon-refresh); } + .jp-RegexIcon { background-image: var(--jp-icon-regex); } + .jp-RunIcon { background-image: var(--jp-icon-run); } + .jp-RunningIcon { background-image: var(--jp-icon-running); } + .jp-SaveIcon { background-image: var(--jp-icon-save); } + .jp-SearchIcon { background-image: var(--jp-icon-search); } + .jp-SettingsIcon { background-image: var(--jp-icon-settings); } + .jp-ShareIcon { background-image: var(--jp-icon-share); } + .jp-SpreadsheetIcon { background-image: var(--jp-icon-spreadsheet); } + .jp-StopIcon { background-image: var(--jp-icon-stop); } + .jp-TabIcon { background-image: var(--jp-icon-tab); } + .jp-TableRowsIcon { background-image: var(--jp-icon-table-rows); } + .jp-TagIcon { background-image: var(--jp-icon-tag); } + .jp-TerminalIcon { background-image: var(--jp-icon-terminal); } + .jp-TextEditorIcon { background-image: var(--jp-icon-text-editor); } + .jp-TocIcon { background-image: var(--jp-icon-toc); } + .jp-TreeViewIcon { background-image: var(--jp-icon-tree-view); } + .jp-TrustedIcon { background-image: var(--jp-icon-trusted); } + .jp-UndoIcon { background-image: var(--jp-icon-undo); } + .jp-UserIcon { background-image: var(--jp-icon-user); } + .jp-UsersIcon { background-image: var(--jp-icon-users); } + .jp-VegaIcon { background-image: var(--jp-icon-vega); } + +.jp-WordIcon { + background-image: var(--jp-icon-word); +} + .jp-YamlIcon { background-image: var(--jp-icon-yaml); } diff --git a/packages/ui-components/style/hoverbox.css b/packages/ui-components/style/hoverbox.css new file mode 100644 index 000000000000..0df355467890 --- /dev/null +++ b/packages/ui-components/style/hoverbox.css @@ -0,0 +1,19 @@ +/*----------------------------------------------------------------------------- +<<<<<<<< HEAD:packages/collaboration-extension/style/base.css +| Copyright (c) Jupyter Development Team. +| Distributed under the terms of the Modified BSD License. +|----------------------------------------------------------------------------*/ + +.jp-UserMenu-Spacer { + flex-grow: 1; + flex-shrink: 1; +======== +| Copyright (c) 2014-2016, Jupyter Development Team. +| +| Distributed under the terms of the Modified BSD License. +|----------------------------------------------------------------------------*/ + +.jp-HoverBox { + position: fixed; +>>>>>>>> 2c9dff7e8343400b5d7d65839cd2f48e8d5ddb69:packages/ui-components/style/hoverbox.css +} diff --git a/packages/ui-components/style/icons.css b/packages/ui-components/style/icons.css index 7278ecbc2f2e..f11ce77ed741 100644 --- a/packages/ui-components/style/icons.css +++ b/packages/ui-components/style/icons.css @@ -11,15 +11,19 @@ .jp-icon0[fill] { fill: var(--jp-inverse-layout-color0); } + .jp-icon1[fill] { fill: var(--jp-inverse-layout-color1); } + .jp-icon2[fill] { fill: var(--jp-inverse-layout-color2); } + .jp-icon3[fill] { fill: var(--jp-inverse-layout-color3); } + .jp-icon4[fill] { fill: var(--jp-inverse-layout-color4); } @@ -27,31 +31,40 @@ .jp-icon0[stroke] { stroke: var(--jp-inverse-layout-color0); } + .jp-icon1[stroke] { stroke: var(--jp-inverse-layout-color1); } + .jp-icon2[stroke] { stroke: var(--jp-inverse-layout-color2); } + .jp-icon3[stroke] { stroke: var(--jp-inverse-layout-color3); } + .jp-icon4[stroke] { stroke: var(--jp-inverse-layout-color4); } + /* recolor the accent elements of an icon */ .jp-icon-accent0[fill] { fill: var(--jp-layout-color0); } + .jp-icon-accent1[fill] { fill: var(--jp-layout-color1); } + .jp-icon-accent2[fill] { fill: var(--jp-layout-color2); } + .jp-icon-accent3[fill] { fill: var(--jp-layout-color3); } + .jp-icon-accent4[fill] { fill: var(--jp-layout-color4); } @@ -59,18 +72,23 @@ .jp-icon-accent0[stroke] { stroke: var(--jp-layout-color0); } + .jp-icon-accent1[stroke] { stroke: var(--jp-layout-color1); } + .jp-icon-accent2[stroke] { stroke: var(--jp-layout-color2); } + .jp-icon-accent3[stroke] { stroke: var(--jp-layout-color3); } + .jp-icon-accent4[stroke] { stroke: var(--jp-layout-color4); } + /* set the color of an icon to transparent */ .jp-icon-none[fill] { fill: none; @@ -79,19 +97,24 @@ .jp-icon-none[stroke] { stroke: none; } + /* brand icon colors. Same for light and dark */ .jp-icon-brand0[fill] { fill: var(--jp-brand-color0); } + .jp-icon-brand1[fill] { fill: var(--jp-brand-color1); } + .jp-icon-brand2[fill] { fill: var(--jp-brand-color2); } + .jp-icon-brand3[fill] { fill: var(--jp-brand-color3); } + .jp-icon-brand4[fill] { fill: var(--jp-brand-color4); } @@ -99,28 +122,36 @@ .jp-icon-brand0[stroke] { stroke: var(--jp-brand-color0); } + .jp-icon-brand1[stroke] { stroke: var(--jp-brand-color1); } + .jp-icon-brand2[stroke] { stroke: var(--jp-brand-color2); } + .jp-icon-brand3[stroke] { stroke: var(--jp-brand-color3); } + .jp-icon-brand4[stroke] { stroke: var(--jp-brand-color4); } + /* warn icon colors. Same for light and dark */ .jp-icon-warn0[fill] { fill: var(--jp-warn-color0); } + .jp-icon-warn1[fill] { fill: var(--jp-warn-color1); } + .jp-icon-warn2[fill] { fill: var(--jp-warn-color2); } + .jp-icon-warn3[fill] { fill: var(--jp-warn-color3); } @@ -128,25 +159,32 @@ .jp-icon-warn0[stroke] { stroke: var(--jp-warn-color0); } + .jp-icon-warn1[stroke] { stroke: var(--jp-warn-color1); } + .jp-icon-warn2[stroke] { stroke: var(--jp-warn-color2); } + .jp-icon-warn3[stroke] { stroke: var(--jp-warn-color3); } + /* icon colors that contrast well with each other and most backgrounds */ .jp-icon-contrast0[fill] { fill: var(--jp-icon-contrast-color0); } + .jp-icon-contrast1[fill] { fill: var(--jp-icon-contrast-color1); } + .jp-icon-contrast2[fill] { fill: var(--jp-icon-contrast-color2); } + .jp-icon-contrast3[fill] { fill: var(--jp-icon-contrast-color3); } @@ -154,16 +192,23 @@ .jp-icon-contrast0[stroke] { stroke: var(--jp-icon-contrast-color0); } + .jp-icon-contrast1[stroke] { stroke: var(--jp-icon-contrast-color1); } + .jp-icon-contrast2[stroke] { stroke: var(--jp-icon-contrast-color2); } + .jp-icon-contrast3[stroke] { stroke: var(--jp-icon-contrast-color3); } +.jp-icon-dot[fill] { + fill: var(--jp-warn-color0); +} + .jp-jupyter-icon-color[fill] { fill: var(--jp-jupyter-icon-color, var(--jp-warn-color0)); } @@ -189,76 +234,30 @@ } .jp-terminal-icon-background-color[fill] { - fill: var(--jp-terminal-icon-background-color, var(--jp-inverse-layout2)); + fill: var( + --jp-terminal-icon-background-color, + var(--jp-inverse-layout-color2) + ); } .jp-text-editor-icon-color[fill] { - fill: var(--jp-text-editor-icon-color, var(--jp-inverse-layout3)); + fill: var(--jp-text-editor-icon-color, var(--jp-inverse-layout-color3)); } .jp-inspector-icon-color[fill] { - fill: var(--jp-inspector-icon-color, var(--jp-inverse-layout3)); + fill: var(--jp-inspector-icon-color, var(--jp-inverse-layout-color3)); } /* CSS for icons in selected filebrowser listing items */ .jp-DirListing-item.jp-mod-selected .jp-icon-selectable[fill] { fill: #fff; } -.jp-DirListing-item.jp-mod-selected .jp-icon-selectable-inverse[fill] { - fill: var(--jp-brand-color1); -} -/* CSS for icons in selected tabs in the sidebar tab manager */ -#tab-manager .lm-TabBar-tab.jp-mod-active .jp-icon-selectable[fill] { - fill: #fff; -} - -#tab-manager .lm-TabBar-tab.jp-mod-active .jp-icon-selectable-inverse[fill] { - fill: var(--jp-brand-color1); -} -#tab-manager - .lm-TabBar-tab.jp-mod-active - .jp-icon-hover - :hover - .jp-icon-selectable[fill] { +.jp-DirListing-item.jp-mod-selected .jp-icon-selectable-inverse[fill] { fill: var(--jp-brand-color1); } -#tab-manager - .lm-TabBar-tab.jp-mod-active - .jp-icon-hover - :hover - .jp-icon-selectable-inverse[fill] { - fill: #fff; -} - -/** - * TODO: come up with non css-hack solution for showing the busy icon on top - * of the close icon - * CSS for complex behavior of close icon of tabs in the sidebar tab manager - */ -#tab-manager - .lm-TabBar-tab.jp-mod-dirty - > .lm-TabBar-tabCloseIcon - > :not(:hover) - > .jp-icon3[fill] { - fill: none; -} -#tab-manager - .lm-TabBar-tab.jp-mod-dirty - > .lm-TabBar-tabCloseIcon - > :not(:hover) - > .jp-icon-busy[fill] { - fill: var(--jp-inverse-layout-color3); -} - -#tab-manager - .lm-TabBar-tab.jp-mod-dirty.jp-mod-active - > .lm-TabBar-tabCloseIcon - > :not(:hover) - > .jp-icon-busy[fill] { - fill: #fff; -} +/* stylelint-disable selector-max-class, selector-max-compound-selectors */ /** * TODO: come up with non css-hack solution for showing the busy icon on top @@ -272,6 +271,7 @@ > .jp-icon3[fill] { fill: none; } + .lm-DockPanel-tabBar .lm-TabBar-tab.lm-mod-closable.jp-mod-dirty > .lm-TabBar-tabCloseIcon @@ -280,6 +280,8 @@ fill: var(--jp-inverse-layout-color3); } +/* stylelint-enable selector-max-class, selector-max-compound-selectors */ + /* CSS for icons in status bar */ #jp-main-statusbar .jp-mod-selected .jp-icon-selectable[fill] { fill: #fff; @@ -288,6 +290,7 @@ #jp-main-statusbar .jp-mod-selected .jp-icon-selectable-inverse[fill] { fill: var(--jp-brand-color1); } + /* special handling for splash icon CSS. While the theme CSS reloads during splash, the splash icon can loose theming. To prevent that, we set a default for its color variable */ diff --git a/packages/ui-components/style/icons/error.svg b/packages/ui-components/style/icons/error.svg new file mode 100644 index 000000000000..c51e0322398c --- /dev/null +++ b/packages/ui-components/style/icons/error.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/ui-components/style/icons/listings/listings-info.svg b/packages/ui-components/style/icons/info.svg similarity index 77% rename from packages/ui-components/style/icons/listings/listings-info.svg rename to packages/ui-components/style/icons/info.svg index 5810866e6594..3e63698eb1d3 100644 --- a/packages/ui-components/style/icons/listings/listings-info.svg +++ b/packages/ui-components/style/icons/info.svg @@ -1,12 +1,12 @@ - - - + diff --git a/packages/ui-components/style/icons/search/filter-dot.svg b/packages/ui-components/style/icons/search/filter-dot.svg new file mode 100644 index 000000000000..4ae72dd6cd7d --- /dev/null +++ b/packages/ui-components/style/icons/search/filter-dot.svg @@ -0,0 +1,8 @@ + + + + diff --git a/packages/ui-components/style/icons/search/filter.svg b/packages/ui-components/style/icons/search/filter.svg new file mode 100644 index 000000000000..92166e025ab5 --- /dev/null +++ b/packages/ui-components/style/icons/search/filter.svg @@ -0,0 +1,5 @@ + + + diff --git a/packages/ui-components/style/icons/search/word.svg b/packages/ui-components/style/icons/search/word.svg new file mode 100644 index 000000000000..8723eff9b7fb --- /dev/null +++ b/packages/ui-components/style/icons/search/word.svg @@ -0,0 +1,10 @@ + + + + diff --git a/packages/ui-components/style/icons/sidebar/user.svg b/packages/ui-components/style/icons/sidebar/user.svg index 54433950475e..c4451a70add3 100644 --- a/packages/ui-components/style/icons/sidebar/user.svg +++ b/packages/ui-components/style/icons/sidebar/user.svg @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/packages/ui-components/style/icons/statusbar/list.svg b/packages/ui-components/style/icons/statusbar/list.svg index 4de147328ecd..40ec017af163 100644 --- a/packages/ui-components/style/icons/statusbar/list.svg +++ b/packages/ui-components/style/icons/statusbar/list.svg @@ -1,3 +1,3 @@ - \ No newline at end of file + diff --git a/packages/ui-components/style/icons/toolbar/collapse-all.svg b/packages/ui-components/style/icons/toolbar/collapse-all.svg new file mode 100644 index 000000000000..c82f2d7cb284 --- /dev/null +++ b/packages/ui-components/style/icons/toolbar/collapse-all.svg @@ -0,0 +1,9 @@ + + + diff --git a/packages/ui-components/style/icons/toolbar/expand-all.svg b/packages/ui-components/style/icons/toolbar/expand-all.svg new file mode 100644 index 000000000000..88d130d4f665 --- /dev/null +++ b/packages/ui-components/style/icons/toolbar/expand-all.svg @@ -0,0 +1,9 @@ + + + diff --git a/packages/ui-components/style/icons/toolbar/table-rows.svg b/packages/ui-components/style/icons/toolbar/table-rows.svg index 0a241774cede..7064eb0debf5 100644 --- a/packages/ui-components/style/icons/toolbar/table-rows.svg +++ b/packages/ui-components/style/icons/toolbar/table-rows.svg @@ -3,4 +3,4 @@ - \ No newline at end of file + diff --git a/packages/ui-components/style/icons/toolbar/tree-view.svg b/packages/ui-components/style/icons/toolbar/tree-view.svg index 48a64351298c..632db6f4c981 100644 --- a/packages/ui-components/style/icons/toolbar/tree-view.svg +++ b/packages/ui-components/style/icons/toolbar/tree-view.svg @@ -3,4 +3,4 @@ - \ No newline at end of file + diff --git a/packages/ui-components/style/iconsalt.css b/packages/ui-components/style/iconsalt.css index c47d7e361e44..44dba2133dbd 100644 --- a/packages/ui-components/style/iconsalt.css +++ b/packages/ui-components/style/iconsalt.css @@ -11,15 +11,19 @@ .jp-icon-alt .jp-icon0[fill] { fill: var(--jp-layout-color0); } + .jp-icon-alt .jp-icon1[fill] { fill: var(--jp-layout-color1); } + .jp-icon-alt .jp-icon2[fill] { fill: var(--jp-layout-color2); } + .jp-icon-alt .jp-icon3[fill] { fill: var(--jp-layout-color3); } + .jp-icon-alt .jp-icon4[fill] { fill: var(--jp-layout-color4); } @@ -27,15 +31,19 @@ .jp-icon-alt .jp-icon0[stroke] { stroke: var(--jp-layout-color0); } + .jp-icon-alt .jp-icon1[stroke] { stroke: var(--jp-layout-color1); } + .jp-icon-alt .jp-icon2[stroke] { stroke: var(--jp-layout-color2); } + .jp-icon-alt .jp-icon3[stroke] { stroke: var(--jp-layout-color3); } + .jp-icon-alt .jp-icon4[stroke] { stroke: var(--jp-layout-color4); } @@ -44,15 +52,19 @@ .jp-icon-alt .jp-icon-accent0[fill] { fill: var(--jp-inverse-layout-color0); } + .jp-icon-alt .jp-icon-accent1[fill] { fill: var(--jp-inverse-layout-color1); } + .jp-icon-alt .jp-icon-accent2[fill] { fill: var(--jp-inverse-layout-color2); } + .jp-icon-alt .jp-icon-accent3[fill] { fill: var(--jp-inverse-layout-color3); } + .jp-icon-alt .jp-icon-accent4[fill] { fill: var(--jp-inverse-layout-color4); } @@ -60,15 +72,19 @@ .jp-icon-alt .jp-icon-accent0[stroke] { stroke: var(--jp-inverse-layout-color0); } + .jp-icon-alt .jp-icon-accent1[stroke] { stroke: var(--jp-inverse-layout-color1); } + .jp-icon-alt .jp-icon-accent2[stroke] { stroke: var(--jp-inverse-layout-color2); } + .jp-icon-alt .jp-icon-accent3[stroke] { stroke: var(--jp-inverse-layout-color3); } + .jp-icon-alt .jp-icon-accent4[stroke] { stroke: var(--jp-inverse-layout-color4); } diff --git a/packages/ui-components/style/iconshover.css b/packages/ui-components/style/iconshover.css index c000c88736d8..9d1a48b04c20 100644 --- a/packages/ui-components/style/iconshover.css +++ b/packages/ui-components/style/iconshover.css @@ -19,15 +19,19 @@ .jp-icon-hover :hover .jp-icon0-hover[fill] { fill: var(--jp-inverse-layout-color0); } + .jp-icon-hover :hover .jp-icon1-hover[fill] { fill: var(--jp-inverse-layout-color1); } + .jp-icon-hover :hover .jp-icon2-hover[fill] { fill: var(--jp-inverse-layout-color2); } + .jp-icon-hover :hover .jp-icon3-hover[fill] { fill: var(--jp-inverse-layout-color3); } + .jp-icon-hover :hover .jp-icon4-hover[fill] { fill: var(--jp-inverse-layout-color4); } @@ -35,15 +39,19 @@ .jp-icon-hover :hover .jp-icon0-hover[stroke] { stroke: var(--jp-inverse-layout-color0); } + .jp-icon-hover :hover .jp-icon1-hover[stroke] { stroke: var(--jp-inverse-layout-color1); } + .jp-icon-hover :hover .jp-icon2-hover[stroke] { stroke: var(--jp-inverse-layout-color2); } + .jp-icon-hover :hover .jp-icon3-hover[stroke] { stroke: var(--jp-inverse-layout-color3); } + .jp-icon-hover :hover .jp-icon4-hover[stroke] { stroke: var(--jp-inverse-layout-color4); } @@ -52,15 +60,19 @@ .jp-icon-hover :hover .jp-icon-accent0-hover[fill] { fill: var(--jp-layout-color0); } + .jp-icon-hover :hover .jp-icon-accent1-hover[fill] { fill: var(--jp-layout-color1); } + .jp-icon-hover :hover .jp-icon-accent2-hover[fill] { fill: var(--jp-layout-color2); } + .jp-icon-hover :hover .jp-icon-accent3-hover[fill] { fill: var(--jp-layout-color3); } + .jp-icon-hover :hover .jp-icon-accent4-hover[fill] { fill: var(--jp-layout-color4); } @@ -68,15 +80,19 @@ .jp-icon-hover :hover .jp-icon-accent0-hover[stroke] { stroke: var(--jp-layout-color0); } + .jp-icon-hover :hover .jp-icon-accent1-hover[stroke] { stroke: var(--jp-layout-color1); } + .jp-icon-hover :hover .jp-icon-accent2-hover[stroke] { stroke: var(--jp-layout-color2); } + .jp-icon-hover :hover .jp-icon-accent3-hover[stroke] { stroke: var(--jp-layout-color3); } + .jp-icon-hover :hover .jp-icon-accent4-hover[stroke] { stroke: var(--jp-layout-color4); } @@ -98,15 +114,19 @@ .jp-icon-hover.jp-icon-alt :hover .jp-icon0-hover[fill] { fill: var(--jp-layout-color0); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon1-hover[fill] { fill: var(--jp-layout-color1); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon2-hover[fill] { fill: var(--jp-layout-color2); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon3-hover[fill] { fill: var(--jp-layout-color3); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon4-hover[fill] { fill: var(--jp-layout-color4); } @@ -114,15 +134,19 @@ .jp-icon-hover.jp-icon-alt :hover .jp-icon0-hover[stroke] { stroke: var(--jp-layout-color0); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon1-hover[stroke] { stroke: var(--jp-layout-color1); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon2-hover[stroke] { stroke: var(--jp-layout-color2); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon3-hover[stroke] { stroke: var(--jp-layout-color3); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon4-hover[stroke] { stroke: var(--jp-layout-color4); } @@ -131,15 +155,19 @@ .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent0-hover[fill] { fill: var(--jp-inverse-layout-color0); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent1-hover[fill] { fill: var(--jp-inverse-layout-color1); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent2-hover[fill] { fill: var(--jp-inverse-layout-color2); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent3-hover[fill] { fill: var(--jp-inverse-layout-color3); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent4-hover[fill] { fill: var(--jp-inverse-layout-color4); } @@ -147,15 +175,19 @@ .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent0-hover[stroke] { stroke: var(--jp-inverse-layout-color0); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent1-hover[stroke] { stroke: var(--jp-inverse-layout-color1); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent2-hover[stroke] { stroke: var(--jp-inverse-layout-color2); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent3-hover[stroke] { stroke: var(--jp-inverse-layout-color3); } + .jp-icon-hover.jp-icon-alt :hover .jp-icon-accent4-hover[stroke] { stroke: var(--jp-inverse-layout-color4); } diff --git a/packages/apputils/style/iframe.css b/packages/ui-components/style/iframe.css similarity index 85% rename from packages/apputils/style/iframe.css rename to packages/ui-components/style/iframe.css index 63bdaa07e3f7..a26405701a6a 100644 --- a/packages/apputils/style/iframe.css +++ b/packages/ui-components/style/iframe.css @@ -13,7 +13,7 @@ } /* -When drag events occur, `p-mod-override-cursor` is added to the body. +When drag events occur, `lm-mod-override-cursor` is added to the body. Because iframes steal all cursor events, the following two rules are necessary to suppress pointer events while resize drags are occurring. There may be a better solution to this problem. @@ -22,7 +22,7 @@ body.lm-mod-override-cursor .jp-IFrame { position: relative; } -body.lm-mod-override-cursor .jp-IFrame:before { +body.lm-mod-override-cursor .jp-IFrame::before { content: ''; position: absolute; top: 0; diff --git a/packages/ui-components/style/index.css b/packages/ui-components/style/index.css index 964b452eec12..175c3e71145f 100644 --- a/packages/ui-components/style/index.css +++ b/packages/ui-components/style/index.css @@ -4,8 +4,5 @@ |----------------------------------------------------------------------------*/ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ -@import url('~@blueprintjs/core/lib/css/blueprint.css'); -@import url('~@blueprintjs/select/lib/css/blueprint-select.css'); @import url('~@lumino/widgets/style/index.css'); - @import url('./base.css'); diff --git a/packages/ui-components/style/index.js b/packages/ui-components/style/index.js index 0368adc4d7c6..bdc940d94bde 100644 --- a/packages/ui-components/style/index.js +++ b/packages/ui-components/style/index.js @@ -4,8 +4,6 @@ |----------------------------------------------------------------------------*/ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ -import '@blueprintjs/core/lib/css/blueprint.css'; -import '@blueprintjs/select/lib/css/blueprint-select.css'; import '@lumino/widgets/style/index.js'; import './base.css'; diff --git a/packages/ui-components/style/rjsfTemplates.css b/packages/ui-components/style/rjsfTemplates.css new file mode 100644 index 000000000000..971ac7d0ee5b --- /dev/null +++ b/packages/ui-components/style/rjsfTemplates.css @@ -0,0 +1,239 @@ +/*----------------------------------------------------------------------------- +| Copyright (c) Jupyter Development Team. +| Distributed under the terms of the Modified BSD License. +|----------------------------------------------------------------------------*/ + +.jp-FormGroup-content fieldset { + border: none; + padding: 0; + min-width: 0; + width: 100%; +} + +/* stylelint-disable selector-max-type */ + +.jp-FormGroup-content fieldset .jp-inputFieldWrapper > input, +.jp-FormGroup-content fieldset .jp-inputFieldWrapper > select, +.jp-FormGroup-content fieldset .jp-inputFieldWrapper > textarea { + font-size: var(--jp-content-font-size2); + border-color: var(--jp-input-border-color); + border-style: solid; + border-radius: var(--jp-border-radius); + border-width: 1px; + padding: 6px 8px; + background: none; + color: var(--jp-ui-font-color0); + height: inherit; +} + +.jp-FormGroup-content .jp-inputFieldWrapper > select > option { + background-color: var(--jp-layout-color1); +} + +.jp-FormGroup-content fieldset input[type='checkbox'] { + position: relative; + top: 2px; + margin-left: 0; +} + +.jp-FormGroup-content button.jp-mod-styled { + cursor: pointer; +} + +.jp-FormGroup-content .checkbox label { + cursor: pointer; + font-size: var(--jp-content-font-size1); +} + +.jp-FormGroup-content .jp-root > fieldset > legend { + display: none; +} + +.jp-FormGroup-content .jp-root > fieldset > p { + display: none; +} + +/** copy of `input.jp-mod-styled:focus` style */ +.jp-FormGroup-content fieldset input:focus, +.jp-FormGroup-content fieldset select:focus { + -moz-outline-radius: unset; + outline: var(--jp-border-width) solid var(--md-blue-500); + outline-offset: -1px; + box-shadow: inset 0 0 4px var(--md-blue-300); +} + +.jp-FormGroup-content fieldset input:hover:not(:focus), +.jp-FormGroup-content fieldset select:hover:not(:focus) { + background-color: var(--jp-border-color2); +} + +/* stylelint-enable selector-max-type */ + +.jp-FormGroup-content .checkbox .field-description { + /* Disable default description field for checkbox: + because other widgets do not have description fields, + we add descriptions to each widget on the field level. + */ + display: none; +} + +.jp-FormGroup-content #root__description { + display: none; +} + +.jp-FormGroup-content .jp-modifiedIndicator { + width: 5px; + background-color: var(--jp-brand-color2); + margin-top: 0; + margin-left: calc(var(--jp-private-settingeditor-modifier-indent) * -1); + flex-shrink: 0; +} + +.jp-FormGroup-content .jp-modifiedIndicator.jp-errorIndicator { + background-color: var(--jp-error-color0); + margin-right: 0.5em; +} + +/* RJSF ARRAY style */ + +.jp-arrayFieldWrapper legend { + font-size: var(--jp-content-font-size2); + color: var(--jp-ui-font-color0); + flex-basis: 100%; + padding: 4px 0; + font-weight: var(--jp-content-heading-font-weight); + border-bottom: 1px solid var(--jp-border-color2); +} + +.jp-arrayFieldWrapper .field-description { + padding: 4px 0; + white-space: pre-wrap; +} + +.jp-arrayFieldWrapper .array-item { + width: 100%; + border: 1px solid var(--jp-border-color2); + border-radius: 4px; + margin: 4px; +} + +.jp-ArrayOperations { + display: flex; + margin-left: 8px; +} + +.jp-ArrayOperationsButton { + margin: 2px; +} + +.jp-ArrayOperationsButton .jp-icon3[fill] { + fill: var(--jp-ui-font-color0); +} + +button.jp-ArrayOperationsButton.jp-mod-styled:disabled { + cursor: not-allowed; + opacity: 0.5; +} + +/* RJSF form validation error */ + +.jp-FormGroup-content .validationErrors { + color: var(--jp-error-color0); +} + +/* Hide panel level error as duplicated the field level error */ +.jp-FormGroup-content .panel.errors { + display: none; +} + +/* RJSF normal content (settings-editor) */ + +.jp-FormGroup-contentNormal { + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.jp-FormGroup-contentNormal .jp-FormGroup-contentItem { + margin-left: 7px; + color: var(--jp-ui-font-color0); +} + +.jp-FormGroup-contentNormal .jp-FormGroup-description { + flex-basis: 100%; + padding: 4px 7px; +} + +.jp-FormGroup-contentNormal .jp-FormGroup-default { + flex-basis: 100%; + padding: 4px 7px; +} + +.jp-FormGroup-contentNormal .jp-FormGroup-fieldLabel { + font-size: var(--jp-content-font-size1); + font-weight: normal; + min-width: 120px; +} + +.jp-FormGroup-contentNormal fieldset:not(:first-child) { + margin-left: 7px; +} + +.jp-FormGroup-contentNormal .field-array-of-string .array-item { + /* Display `jp-ArrayOperations` buttons side-by-side with content except + for small screens where flex-wrap will place them one below the other. + */ + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.jp-FormGroup-contentNormal .jp-objectFieldWrapper .form-group { + padding: 2px 8px 2px var(--jp-private-settingeditor-modifier-indent); + margin-top: 2px; +} + +/* RJSF compact content (metadata-form) */ + +.jp-FormGroup-content.jp-FormGroup-contentCompact { + width: 100%; +} + +.jp-FormGroup-contentCompact .form-group { + display: flex; + padding: 0.5em 0.2em 0.5em 0; +} + +.jp-FormGroup-contentCompact + .jp-FormGroup-compactTitle + .jp-FormGroup-description { + font-size: var(--jp-ui-font-size1); + color: var(--jp-ui-font-color2); +} + +.jp-FormGroup-contentCompact .jp-FormGroup-fieldLabel { + padding-bottom: 0.3em; +} + +.jp-FormGroup-contentCompact .jp-inputFieldWrapper .form-control { + width: 100%; + box-sizing: border-box; +} + +.jp-FormGroup-contentCompact .jp-arrayFieldWrapper .jp-FormGroup-compactTitle { + padding-bottom: 7px; +} + +.jp-FormGroup-contentCompact + .jp-objectFieldWrapper + .jp-objectFieldWrapper + .form-group { + padding: 2px 8px 2px var(--jp-private-settingeditor-modifier-indent); + margin-top: 2px; +} + +.jp-FormGroup-contentCompact ul.error-detail { + margin-block-start: 0.5em; + margin-block-end: 0.5em; + padding-inline-start: 1em; +} diff --git a/packages/ui-components/style/sidepanel.css b/packages/ui-components/style/sidepanel.css new file mode 100644 index 000000000000..553a6ab71d38 --- /dev/null +++ b/packages/ui-components/style/sidepanel.css @@ -0,0 +1,105 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +.jp-SidePanel { + display: flex; + flex-direction: column; + min-width: var(--jp-sidebar-min-width); + overflow-y: auto; + color: var(--jp-ui-font-color1); + background: var(--jp-layout-color1); + font-size: var(--jp-ui-font-size1); +} + +.jp-SidePanel-header { + flex: 0 0 auto; + display: flex; + border-bottom: var(--jp-border-width) solid var(--jp-border-color2); + font-size: var(--jp-ui-font-size0); + font-weight: 600; + letter-spacing: 1px; + margin: 0; + padding: 2px; + text-transform: uppercase; +} + +.jp-SidePanel-toolbar { + flex: 0 0 auto; +} + +.jp-SidePanel-content { + flex: 1 1 auto; +} + +.jp-SidePanel-toolbar, +.jp-AccordionPanel-toolbar { + height: var(--jp-private-toolbar-height); +} + +.jp-SidePanel-toolbar.jp-Toolbar-micro { + display: none; +} + +.lm-AccordionPanel .jp-AccordionPanel-title { + box-sizing: border-box; + line-height: 25px; + margin: 0; + display: flex; + align-items: center; + background: var(--jp-layout-color1); + color: var(--jp-ui-font-color1); + border-bottom: var(--jp-border-width) solid var(--jp-toolbar-border-color); + box-shadow: var(--jp-toolbar-box-shadow); + font-size: var(--jp-ui-font-size0); +} + +.jp-AccordionPanel-title { + cursor: pointer; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + text-transform: uppercase; +} + +.lm-AccordionPanel[data-orientation='horizontal'] > .jp-AccordionPanel-title { + /* Title is rotated for horizontal accordion panel using CSS */ + display: block; + transform-origin: top left; + transform: rotate(-90deg) translate(-100%); +} + +.jp-AccordionPanel-title .lm-AccordionPanel-titleLabel { + user-select: none; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.jp-AccordionPanel-title .lm-AccordionPanel-titleCollapser { + transform: rotate(-90deg); + margin: auto 0; + height: 16px; +} + +.jp-AccordionPanel-title.lm-mod-expanded .lm-AccordionPanel-titleCollapser { + transform: rotate(0deg); +} + +.lm-AccordionPanel .jp-AccordionPanel-toolbar { + background: none; + box-shadow: none; + border: none; + margin-left: auto; +} + +.lm-AccordionPanel .lm-SplitPanel-handle:hover { + background: var(--jp-layout-color3); +} + +.jp-text-truncated { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/packages/apputils/style/spinner.css b/packages/ui-components/style/spinner.css similarity index 89% rename from packages/apputils/style/spinner.css rename to packages/ui-components/style/spinner.css index ee5743ac91f6..9bb0774d099f 100644 --- a/packages/apputils/style/spinner.css +++ b/packages/ui-components/style/spinner.css @@ -32,21 +32,23 @@ rgba(255, 255, 255, 0) 42% ); position: relative; - animation: load3 1s infinite linear, fadeIn 1s; + animation: + load3 1s infinite linear, + fadeIn 1s; } -.jp-SpinnerContent:before { +.jp-SpinnerContent::before { width: 50%; height: 50%; background: #f37626; - border-radius: 100% 0 0 0; + border-radius: 100% 0 0; position: absolute; top: 0; left: 0; content: ''; } -.jp-SpinnerContent:after { +.jp-SpinnerContent::after { background: var(--jp-layout-color0); width: 75%; height: 75%; @@ -64,6 +66,7 @@ 0% { opacity: 0; } + 100% { opacity: 1; } @@ -73,6 +76,7 @@ 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } diff --git a/packages/apputils/style/styling.css b/packages/ui-components/style/styling.css similarity index 87% rename from packages/apputils/style/styling.css rename to packages/ui-components/style/styling.css index de5146bb2841..0ab8897f0ac6 100644 --- a/packages/apputils/style/styling.css +++ b/packages/ui-components/style/styling.css @@ -12,7 +12,7 @@ button.jp-mod-styled { text-align: center; line-height: 32px; height: 32px; - padding: 0px 12px; + padding: 0 12px; letter-spacing: 0.8px; outline: none; appearance: none; @@ -47,29 +47,20 @@ input.jp-mod-styled:focus { box-shadow: inset 0 0 4px var(--md-blue-300); } -.jp-FileDialog-Checkbox { - margin-top: 35px; - display: flex; - flex-direction: row; - align-items: end; - width: 100%; -} - -.jp-FileDialog-Checkbox > label { - flex: 1 1 auto; -} - .jp-select-wrapper { display: flex; position: relative; flex-direction: column; padding: 1px; background-color: var(--jp-layout-color1); - height: 28px; box-sizing: border-box; margin-bottom: 12px; } +.jp-select-wrapper:not(.multiple) { + height: 28px; +} + .jp-select-wrapper.jp-mod-focused select.jp-mod-styled { border: var(--jp-border-width) solid var(--jp-input-active-border-color); box-shadow: var(--jp-input-box-shadow); @@ -77,25 +68,32 @@ input.jp-mod-styled:focus { } select.jp-mod-styled:hover { - background-color: var(--jp-layout-color1); cursor: pointer; color: var(--jp-ui-font-color0); background-color: var(--jp-input-hover-background); - box-shadow: inset 0 0px 1px rgba(0, 0, 0, 0.5); + box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.5); } select.jp-mod-styled { flex: 1 1 auto; - height: 32px; width: 100%; font-size: var(--jp-ui-font-size2); background: var(--jp-input-background); color: var(--jp-ui-font-color0); padding: 0 25px 0 8px; border: var(--jp-border-width) solid var(--jp-input-border-color); - border-radius: 0px; + border-radius: 0; outline: none; appearance: none; -webkit-appearance: none; -moz-appearance: none; } + +select.jp-mod-styled:not([multiple]) { + height: 32px; +} + +select.jp-mod-styled[multiple] { + max-height: 200px; + overflow-y: auto; +} diff --git a/packages/ui-components/style/switch.css b/packages/ui-components/style/switch.css index 2ccc0f6ccdc5..5e0cc750d40a 100644 --- a/packages/ui-components/style/switch.css +++ b/packages/ui-components/style/switch.css @@ -21,6 +21,7 @@ .jp-switch-label { margin-right: 5px; + font-family: var(--jp-ui-font-family); } .jp-switch-track { @@ -40,7 +41,7 @@ height: 10px; width: 10px; margin: 3px; - left: 0px; + left: 0; background-color: var(--jp-ui-inverse-font-color1); -webkit-transition: 0.4s; transition: 0.4s; diff --git a/packages/apputils/style/toolbar.css b/packages/ui-components/style/toolbar.css similarity index 94% rename from packages/apputils/style/toolbar.css rename to packages/ui-components/style/toolbar.css index d05e60e5d984..aa06951a9766 100644 --- a/packages/apputils/style/toolbar.css +++ b/packages/ui-components/style/toolbar.css @@ -60,8 +60,8 @@ div.jp-ToolbarButton { appearance: none; -webkit-appearance: none; -moz-appearance: none; - padding: 0px; - margin: 0px; + padding: 0; + margin: 0; } button.jp-ToolbarButtonComponent { @@ -72,8 +72,8 @@ button.jp-ToolbarButtonComponent { appearance: none; -webkit-appearance: none; -moz-appearance: none; - padding: 0px 6px; - margin: 0px; + padding: 0 6px; + margin: 0; height: 24px; border-radius: var(--jp-border-radius); display: flex; @@ -88,8 +88,8 @@ button.jp-ToolbarButtonComponent:disabled { opacity: 0.4; } -button.jp-ToolbarButtonComponent span { - padding: 0px; +button.jp-ToolbarButtonComponent > span { + padding: 0; flex: 0 0 auto; } @@ -98,6 +98,7 @@ button.jp-ToolbarButtonComponent .jp-ToolbarButtonComponent-label { line-height: 100%; padding-left: 2px; color: var(--jp-ui-font-color1); + font-family: var(--jp-ui-font-family); } #jp-main-dock-panel[data-mode='single-document'] diff --git a/packages/ui-components/style/unused/jupyterlab.svg b/packages/ui-components/style/unused/jupyterlab.svg index 347251360aa0..6e6c65f1d85b 100644 --- a/packages/ui-components/style/unused/jupyterlab.svg +++ b/packages/ui-components/style/unused/jupyterlab.svg @@ -105,4 +105,4 @@ - \ No newline at end of file + diff --git a/packages/ui-components/style/windowedlist.css b/packages/ui-components/style/windowedlist.css new file mode 100644 index 000000000000..5d132b01632c --- /dev/null +++ b/packages/ui-components/style/windowedlist.css @@ -0,0 +1,20 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +.jp-WindowedPanel-outer { + position: relative; + overflow-y: auto; +} + +.jp-WindowedPanel-inner { + position: relative; +} + +.jp-WindowedPanel-window { + position: absolute; + left: 0; + right: 0; + overflow: visible; +} diff --git a/packages/ui-components/test/hoverbox.spec.ts b/packages/ui-components/test/hoverbox.spec.ts new file mode 100644 index 000000000000..829fbe6685eb --- /dev/null +++ b/packages/ui-components/test/hoverbox.spec.ts @@ -0,0 +1,227 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { HoverBox } from '@jupyterlab/ui-components'; + +function createDomRect(options: { + x: number; + y: number; + width: number; + height: number; +}): DOMRect { + return { + ...options, + bottom: options.x + options.height, + top: options.y, + left: options.x, + right: options.x + options.width, + toJSON: () => 'DummyDOMRect' + }; +} + +function createPointAnchor(options: { x: number; y: number }): DOMRect { + return createDomRect({ ...options, width: 0, height: 0 }); +} + +describe('@jupyterlab/ui-components', () => { + describe('HoverBox.setGeometry()', () => { + let host: HTMLElement; + let node: HTMLElement; + let anchor: DOMRect; + let defaults: () => { + host: HTMLElement; + node: HTMLElement; + anchor: DOMRect; + maxHeight: number; + minHeight: number; + }; + beforeEach(() => { + host = document.createElement('div'); + node = document.createElement('div'); + window.innerHeight = 100; + window.innerWidth = 100; + anchor = createPointAnchor({ + x: 50, + y: 50 + }); + defaults = () => { + return { host, anchor, node, maxHeight: 100, minHeight: 1 }; + }; + jest.spyOn(host, 'getBoundingClientRect').mockReturnValue( + createDomRect({ + x: 20, + y: 20, + width: 60, // right = 80 + height: 60 // bottom = 80 + }) + ); + }); + + it('should position node next to the anchor', () => { + jest.spyOn(node, 'getBoundingClientRect').mockImplementation(() => { + return createDomRect({ + x: parseInt(node.style.left, 10), + y: parseInt(node.style.top, 10), + width: 10, + height: 0 + }); + }); + + HoverBox.setGeometry(defaults()); + expect(node.style.left).toBe('50px'); + expect(node.style.top).toBe('50px'); + }); + + it('should position node within the window', () => { + // anchor position (50) + node width width (60) exceeds window width (100) + jest.spyOn(node, 'getBoundingClientRect').mockImplementation(() => { + return createDomRect({ + x: parseInt(node.style.left, 10), + y: parseInt(node.style.top, 10), + width: 60, + height: 1 + }); + }); + + HoverBox.setGeometry(defaults()); + expect(node.style.left).toBe('40px'); + }); + + describe('outOfViewDisplay = `stick-outside`', () => { + it('should keep the left edge of the node within the host', () => { + jest.spyOn(node, 'getBoundingClientRect').mockImplementation(() => { + return createDomRect({ + x: parseInt(node.style.left, 10), + y: parseInt(node.style.top, 10), + width: 10, + height: 0 + }); + }); + + anchor = createPointAnchor({ + x: 70, + y: 50 + }); + HoverBox.setGeometry({ + ...defaults(), + outOfViewDisplay: { + right: 'stick-outside' + } + }); + expect(node.style.left).toBe('70px'); + + anchor = createPointAnchor({ + x: 85, + y: 50 + }); + HoverBox.setGeometry({ + ...defaults(), + outOfViewDisplay: { + right: 'stick-outside' + } + }); + expect(node.style.left).toBe('80px'); + }); + }); + + describe('outOfViewDisplay = `stick-inside`', () => { + it('should keep the right edge of the node within the host', () => { + jest.spyOn(node, 'getBoundingClientRect').mockImplementation(() => { + return createDomRect({ + x: parseInt(node.style.left, 10), + y: parseInt(node.style.top, 10), + width: 10, + height: 0 + }); + }); + + anchor = createPointAnchor({ + x: 85, + y: 50 + }); + + HoverBox.setGeometry({ + ...defaults(), + outOfViewDisplay: { + right: 'stick-inside' + } + }); + // host right edge (80px) - node width (10px) + expect(node.style.left).toBe('70px'); + }); + + it('should also work when adjusting for window right edge', () => { + // anchor position (50) + node width width (60) exceeds window right edge (100) + jest.spyOn(node, 'getBoundingClientRect').mockImplementation(() => { + return createDomRect({ + x: parseInt(node.style.left, 10), + y: parseInt(node.style.top, 10), + width: 60, + height: 1 + }); + }); + + HoverBox.setGeometry({ + ...defaults(), + outOfViewDisplay: { + right: 'stick-inside' + } + }); + // host right edge (80px) - node width (60px) + expect(node.style.left).toBe('20px'); + }); + + it('should keep the left edge of the node within the host', () => { + jest.spyOn(node, 'getBoundingClientRect').mockImplementation(() => { + return createDomRect({ + x: parseInt(node.style.left, 10), + y: parseInt(node.style.top, 10), + width: 10, + height: 0 + }); + }); + + anchor = createPointAnchor({ + x: 15, + y: 50 + }); + + HoverBox.setGeometry({ + ...defaults(), + outOfViewDisplay: { + left: 'stick-inside' + } + }); + // host left edge (20px) + expect(node.style.left).toBe('20px'); + }); + + it('should also work when adjusting for window left edge', () => { + anchor = createPointAnchor({ + x: -60, + y: 50 + }); + // anchor position (-60) + node width width (30) exceeds window left edge (0) + jest.spyOn(node, 'getBoundingClientRect').mockImplementation(() => { + return createDomRect({ + x: parseInt(node.style.left, 10), + y: parseInt(node.style.top, 10), + width: 30, + height: 1 + }); + }); + + HoverBox.setGeometry({ + ...defaults(), + outOfViewDisplay: { + left: 'stick-inside' + } + }); + // host left edge (20px) + expect(node.style.left).toBe('20px'); + }); + }); + }); +}); diff --git a/packages/apputils/test/iframe.spec.ts b/packages/ui-components/test/iframe.spec.ts similarity index 96% rename from packages/apputils/test/iframe.spec.ts rename to packages/ui-components/test/iframe.spec.ts index eb9464d6dbae..a09354159673 100644 --- a/packages/apputils/test/iframe.spec.ts +++ b/packages/ui-components/test/iframe.spec.ts @@ -1,9 +1,9 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IFrame } from '@jupyterlab/apputils'; +import { IFrame } from '@jupyterlab/ui-components'; -describe('@jupyterlab/apputils', () => { +describe('@jupyterlab/ui-components', () => { describe('IFrame', () => { describe('#constructor()', () => { it('should create a new iframe widget', () => { diff --git a/packages/mainmenu/test/labmenu.spec.ts b/packages/ui-components/test/menu.spec.ts similarity index 81% rename from packages/mainmenu/test/labmenu.spec.ts rename to packages/ui-components/test/menu.spec.ts index c02ab33c9b70..0a371aec3e01 100644 --- a/packages/mainmenu/test/labmenu.spec.ts +++ b/packages/ui-components/test/menu.spec.ts @@ -1,15 +1,41 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { JupyterLabMenu } from '@jupyterlab/mainmenu'; +import { IRankedMenu, RankedMenu } from '@jupyterlab/ui-components'; import { ArrayExt } from '@lumino/algorithm'; import { CommandRegistry } from '@lumino/commands'; import { Menu } from '@lumino/widgets'; -describe('@jupyterlab/mainmenu', () => { - describe('JupyterLabMenu', () => { +describe('@jupyterlab/ui-components', () => { + describe('IRankedMenu', () => { let commands: CommandRegistry; - let menu: JupyterLabMenu; + const id = 'test-command'; + const options: CommandRegistry.ICommandOptions = { + execute: jest.fn() + }; + + beforeAll(() => { + commands = new CommandRegistry(); + commands.addCommand(id, options); + }); + describe('#addItem', () => { + it('should return a disposable item', () => { + const menu = new RankedMenu({ commands }) as IRankedMenu; + + const item = menu.addItem({ command: id }); + + expect(menu.items.length).toEqual(1); + + item.dispose(); + + expect(menu.items.length).toEqual(0); + }); + }); + }); + + describe('RankedMenu', () => { + let commands: CommandRegistry; + let menu: RankedMenu; beforeAll(() => { commands = new CommandRegistry(); @@ -32,7 +58,7 @@ describe('@jupyterlab/mainmenu', () => { }); beforeEach(() => { - menu = new JupyterLabMenu({ commands }); + menu = new RankedMenu({ commands }); }); afterEach(() => { @@ -41,16 +67,16 @@ describe('@jupyterlab/mainmenu', () => { describe('#constructor()', () => { it('should construct a new main menu', () => { - expect(menu).toBeInstanceOf(JupyterLabMenu); + expect(menu).toBeInstanceOf(RankedMenu); expect(menu).toBeInstanceOf(Menu); }); it('should accept useSeparators as an option', () => { - const menu1 = new JupyterLabMenu({ + const menu1 = new RankedMenu({ commands, includeSeparators: false }); - const menu2 = new JupyterLabMenu({ commands, includeSeparators: true }); + const menu2 = new RankedMenu({ commands, includeSeparators: true }); menu1.addGroup([{ command: 'run1' }, { command: 'run2' }]); menu2.addGroup([{ command: 'run1' }, { command: 'run2' }]); @@ -59,12 +85,12 @@ describe('@jupyterlab/mainmenu', () => { }); it('should accept rank as an option', () => { - const menu = new JupyterLabMenu({ commands, rank: 22 }); + const menu = new RankedMenu({ commands, rank: 22 }); expect(menu.rank).toEqual(22); }); it('should have rank undefined by default', () => { - const menu = new JupyterLabMenu({ commands }); + const menu = new RankedMenu({ commands }); expect(menu.rank).toBeUndefined(); }); }); @@ -75,7 +101,7 @@ describe('@jupyterlab/mainmenu', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore menu.rank = 42; - }).toThrowError(); + }).toThrow(); }); }); diff --git a/packages/apputils/test/styling.spec.ts b/packages/ui-components/test/styling.spec.ts similarity index 96% rename from packages/apputils/test/styling.spec.ts rename to packages/ui-components/test/styling.spec.ts index 4df083531ed5..890c9e607cca 100644 --- a/packages/apputils/test/styling.spec.ts +++ b/packages/ui-components/test/styling.spec.ts @@ -1,11 +1,11 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { Styling } from '@jupyterlab/apputils'; +import { Styling } from '@jupyterlab/ui-components'; import { h, VirtualDOM } from '@lumino/virtualdom'; import { simulate } from 'simulate-event'; -describe('@jupyterlab/apputils', () => { +describe('@jupyterlab/ui-components', () => { describe('Styling', () => { describe('.styleNode()', () => { it('should style descendant nodes for select, input and button', () => { diff --git a/packages/ui-components/test/svg.d.ts b/packages/ui-components/test/svg.d.ts index 52c76d82452d..90e4deda5555 100644 --- a/packages/ui-components/test/svg.d.ts +++ b/packages/ui-components/test/svg.d.ts @@ -1,8 +1,6 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -// Distributed under the terms of the Modified BSD License. - // including this file in a package allows for the use of import statements // with svg files. Example: `import xSvg from 'path/xSvg.svg'` diff --git a/packages/ui-components/test/tabbarsvg.spec.ts b/packages/ui-components/test/tabbarsvg.spec.ts new file mode 100644 index 000000000000..b591e350c743 --- /dev/null +++ b/packages/ui-components/test/tabbarsvg.spec.ts @@ -0,0 +1,36 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { TabBarSvg } from '@jupyterlab/ui-components'; +import { Title, Widget } from '@lumino/widgets'; +import { VirtualDOM } from '@lumino/virtualdom'; + +describe('.Renderer', () => { + let title: Title; + + beforeEach(() => { + let owner = new Widget(); + title = new Title({ + owner, + label: 'foo', + closable: true, + iconClass: 'bar', + className: 'fizz', + caption: 'this is a caption' + }); + }); + + describe('#renderCloseIcon()', () => { + it('should render the close icon and check the title element matches the title', () => { + let renderer = new TabBarSvg.Renderer(); + let vNode = renderer.renderCloseIcon({ + title, + current: true, + zIndex: 1 + }); + let icon = VirtualDOM.realize(vNode); + expect(icon.className).toContain('lm-TabBar-tabCloseIcon'); + expect(icon.title).toEqual('Close ' + title.label); + }); + }); +}); diff --git a/packages/ui-components/test/toolbar.spec.ts b/packages/ui-components/test/toolbar.spec.ts new file mode 100644 index 000000000000..e1d2c17dd923 --- /dev/null +++ b/packages/ui-components/test/toolbar.spec.ts @@ -0,0 +1,658 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { + blankIcon, + bugDotIcon, + bugIcon, + CommandToolbarButton, + jupyterIcon, + ReactiveToolbar, + Toolbar, + ToolbarButton +} from '@jupyterlab/ui-components'; +import { framePromise, JupyterServer } from '@jupyterlab/testing'; +import { CommandRegistry } from '@lumino/commands'; +import { ReadonlyPartialJSONObject } from '@lumino/coreutils'; +import { PanelLayout, Widget } from '@lumino/widgets'; +import { simulate } from 'simulate-event'; + +const server = new JupyterServer(); + +beforeAll(async () => { + await server.start(); +}, 30000); + +afterAll(async () => { + await server.shutdown(); +}); + +describe('@jupyterlab/ui-components', () => { + describe('CommandToolbarButton', () => { + let commands: CommandRegistry; + const id = 'test-command'; + const options: CommandRegistry.ICommandOptions = { + execute: jest.fn() + }; + + beforeEach(() => { + commands = new CommandRegistry(); + }); + + it('should render a command', async () => { + commands.addCommand(id, options); + const button = new CommandToolbarButton({ + commands, + id + }); + + Widget.attach(button, document.body); + await framePromise(); + + expect(button.hasClass('jp-CommandToolbarButton')).toBe(true); + simulate(button.node.firstElementChild!, 'mousedown'); + expect(options.execute).toHaveBeenCalledTimes(1); + }); + + it('should render the label command', async () => { + const label = 'This is a test label'; + commands.addCommand(id, { ...options, label }); + const button = new CommandToolbarButton({ + commands, + id + }); + + Widget.attach(button, document.body); + await framePromise(); + + expect(button.node.textContent).toMatch(label); + }); + + it('should render the customized label command', async () => { + const label = 'This is a test label'; + const buttonLabel = 'This is the button label'; + commands.addCommand(id, { ...options, label }); + const button = new CommandToolbarButton({ + commands, + id, + label: buttonLabel + }); + + Widget.attach(button, document.body); + await framePromise(); + + expect(button.node.textContent).toMatch(buttonLabel); + expect(button.node.textContent).not.toMatch(label); + }); + + it('should render the icon command', async () => { + const icon = jupyterIcon; + commands.addCommand(id, { ...options, icon }); + const button = new CommandToolbarButton({ + commands, + id + }); + + Widget.attach(button, document.body); + await framePromise(); + + expect(button.node.getElementsByTagName('svg')[0].dataset.icon).toMatch( + icon.name + ); + }); + + it('should render the customized icon command', async () => { + const icon = jupyterIcon; + const buttonIcon = blankIcon; + commands.addCommand(id, { ...options, icon }); + const button = new CommandToolbarButton({ + commands, + id, + icon: buttonIcon + }); + + Widget.attach(button, document.body); + await framePromise(); + + const iconSVG = button.node.getElementsByTagName('svg')[0]; + expect(iconSVG.dataset.icon).toMatch(buttonIcon.name); + expect(iconSVG.dataset.icon).not.toMatch(icon.name); + }); + }); + + describe('Toolbar', () => { + let widget: Toolbar; + + beforeEach(async () => { + widget = new Toolbar(); + }, 30000); + + afterEach(async () => { + widget.dispose(); + }); + + describe('#constructor()', () => { + it('should construct a new toolbar widget', () => { + const widget = new Toolbar(); + expect(widget).toBeInstanceOf(Toolbar); + }); + + it('should add the `jp-Toolbar` class', () => { + const widget = new Toolbar(); + expect(widget.hasClass('jp-Toolbar')).toBe(true); + }); + }); + + describe('#names()', () => { + it('should get an ordered list the toolbar item names', () => { + widget.addItem('foo', new Widget()); + widget.addItem('bar', new Widget()); + widget.addItem('baz', new Widget()); + expect(Array.from(widget.names())).toEqual(['foo', 'bar', 'baz']); + }); + }); + + describe('#addItem()', () => { + it('should add an item to the toolbar', () => { + const item = new Widget(); + expect(widget.addItem('test', item)).toBe(true); + expect(Array.from(widget.names())).toContain('test'); + }); + + it('should add the `jp-Toolbar-item` class to the widget', () => { + const item = new Widget(); + widget.addItem('test', item); + expect(item.hasClass('jp-Toolbar-item')).toBe(true); + }); + + it('should return false if the name is already used', () => { + widget.addItem('test', new Widget()); + expect(widget.addItem('test', new Widget())).toBe(false); + }); + }); + + describe('#insertItem()', () => { + it('should insert the item into the toolbar', () => { + widget.addItem('a', new Widget()); + widget.addItem('b', new Widget()); + widget.insertItem(1, 'c', new Widget()); + expect(Array.from(widget.names())).toEqual(['a', 'c', 'b']); + }); + + it('should clamp the bounds', () => { + widget.addItem('a', new Widget()); + widget.addItem('b', new Widget()); + widget.insertItem(10, 'c', new Widget()); + expect(Array.from(widget.names())).toEqual(['a', 'b', 'c']); + }); + }); + + describe('#insertAfter()', () => { + it('should insert an item into the toolbar after `c`', () => { + widget.addItem('a', new Widget()); + widget.addItem('b', new Widget()); + widget.insertItem(1, 'c', new Widget()); + widget.insertAfter('c', 'd', new Widget()); + expect(Array.from(widget.names())).toEqual(['a', 'c', 'd', 'b']); + }); + + it('should return false if the target item does not exist', () => { + widget.addItem('a', new Widget()); + widget.addItem('b', new Widget()); + const value = widget.insertAfter('c', 'd', new Widget()); + expect(value).toBe(false); + }); + }); + + describe('#insertBefore()', () => { + it('should insert an item into the toolbar before `c`', () => { + widget.addItem('a', new Widget()); + widget.addItem('b', new Widget()); + widget.insertItem(1, 'c', new Widget()); + widget.insertBefore('c', 'd', new Widget()); + expect(Array.from(widget.names())).toEqual(['a', 'd', 'c', 'b']); + }); + + it('should return false if the target item does not exist', () => { + widget.addItem('a', new Widget()); + widget.addItem('b', new Widget()); + const value = widget.insertBefore('c', 'd', new Widget()); + expect(value).toBe(false); + }); + }); + + describe('.createFromCommand', () => { + const commands = new CommandRegistry(); + const testLogCommandId = 'test:toolbar-log'; + const logArgs: ReadonlyPartialJSONObject[] = []; + let enabled = false; + let toggled = true; + let visible = false; + commands.addCommand(testLogCommandId, { + execute: args => { + logArgs.push(args); + }, + label: 'Test log command label', + caption: 'Test log command caption', + usage: 'Test log command usage', + iconClass: 'test-icon-class', + className: 'test-log-class', + isEnabled: () => enabled, + isToggled: () => toggled, + isVisible: () => visible + }); + + async function render(button: CommandToolbarButton) { + button.update(); + await framePromise(); + expect(button.renderPromise).toBeDefined(); + await button.renderPromise; + } + + it('should create a button', () => { + const button = new CommandToolbarButton({ + commands, + id: testLogCommandId + }); + expect(button).toBeInstanceOf(CommandToolbarButton); + button.dispose(); + }); + + it('should add main class', async () => { + const button = new CommandToolbarButton({ + commands, + id: testLogCommandId + }); + await render(button); + const buttonNode = button.node.firstChild as HTMLButtonElement; + expect(buttonNode.classList.contains('test-log-class')).toBe(true); + button.dispose(); + }); + + it('should add an icon with icon class and label', async () => { + const button = new CommandToolbarButton({ + commands, + id: testLogCommandId + }); + await render(button); + const buttonNode = button.node.firstChild as HTMLButtonElement; + expect(buttonNode.title).toBe('Test log command caption'); + const iconNode = buttonNode.firstChild as HTMLElement; + expect(iconNode.classList.contains('test-icon-class')).toBe(true); + button.dispose(); + }); + + it('should apply state classes', async () => { + enabled = false; + toggled = true; + visible = false; + const button = new CommandToolbarButton({ + commands, + id: testLogCommandId + }); + await render(button); + const buttonNode = button.node.firstChild as HTMLButtonElement; + expect(buttonNode.disabled).toBe(true); + expect(buttonNode.classList.contains('lm-mod-toggled')).toBe(true); + expect(buttonNode.classList.contains('lm-mod-hidden')).toBe(true); + button.dispose(); + }); + + it('should update state classes', async () => { + enabled = false; + toggled = true; + visible = false; + const button = new CommandToolbarButton({ + commands, + id: testLogCommandId + }); + await render(button); + const buttonNode = button.node.firstChild as HTMLButtonElement; + expect(buttonNode.disabled).toBe(true); + expect(buttonNode.classList.contains('lm-mod-toggled')).toBe(true); + expect(buttonNode.classList.contains('lm-mod-hidden')).toBe(true); + enabled = true; + visible = true; + commands.notifyCommandChanged(testLogCommandId); + await framePromise(); + await button.renderPromise; + expect(buttonNode.disabled).toBe(false); + expect(buttonNode.classList.contains('lm-mod-toggled')).toBe(true); + expect(buttonNode.classList.contains('lm-mod-hidden')).toBe(false); + enabled = false; + visible = false; + button.dispose(); + }); + + it('should use the command label if no icon class/label', async () => { + const id = 'to-be-removed'; + const cmd = commands.addCommand(id, { + execute: () => { + return; + }, + label: 'Label-only button' + }); + const button = new CommandToolbarButton({ + commands, + id + }); + await render(button); + const buttonNode = button.node.firstChild as HTMLButtonElement; + expect(buttonNode.textContent).toBe('Label-only button'); + cmd.dispose(); + }); + + it('should update the node content on command change event', async () => { + const id = 'to-be-removed'; + let iconClassValue: string = ''; + const cmd = commands.addCommand(id, { + execute: () => { + /* no op */ + }, + label: 'Label-only button', + iconClass: () => iconClassValue ?? '' + }); + const button = new CommandToolbarButton({ + commands, + id + }); + await render(button); + const buttonNode = button.node.firstChild as HTMLButtonElement; + expect(buttonNode.textContent).toBe('Label-only button'); + expect(buttonNode.classList.contains(iconClassValue)).toBe(false); + + iconClassValue = 'updated-icon-class'; + commands.notifyCommandChanged(id); + await render(button); + const iconNode = buttonNode.firstChild as HTMLElement; + expect(iconNode.classList.contains(iconClassValue)).toBe(true); + cmd.dispose(); + }); + }); + }); + + describe('ReactiveToolbar', () => { + let toolbar: ReactiveToolbar; + + beforeEach(() => { + toolbar = new ReactiveToolbar(); + Widget.attach(toolbar, document.body); + }); + + afterEach(() => { + toolbar.dispose(); + }); + + describe('#constructor()', () => { + it('should append a node to body for the pop-up', () => { + const popup = document.body.querySelector( + '.jp-Toolbar-responsive-popup' + ); + expect(popup).toBeDefined(); + expect(popup!.parentNode!.nodeName).toEqual('BODY'); + }); + }); + + describe('#addItem()', () => { + it('should insert item before the toolbar pop-up button', () => { + const w = new Widget(); + toolbar.addItem('test', w); + expect( + (toolbar.layout as PanelLayout).widgets.findIndex(v => v === w) + ).toEqual((toolbar.layout as PanelLayout).widgets.length - 2); + }); + }); + + describe('#insertItem()', () => { + it('should insert item before the toolbar pop-up button', () => { + const w = new Widget(); + toolbar.insertItem(2, 'test', w); + expect( + (toolbar.layout as PanelLayout).widgets.findIndex(v => v === w) + ).toEqual((toolbar.layout as PanelLayout).widgets.length - 2); + }); + }); + + describe('#insertAfter()', () => { + it('should not insert item after the toolbar pop-up button', () => { + const w = new Widget(); + const r = toolbar.insertAfter('toolbar-popup-opener', 'test', w); + expect(r).toEqual(false); + expect( + (toolbar.layout as PanelLayout).widgets.findIndex(v => v === w) + ).toEqual(-1); + }); + }); + }); + + describe('ToolbarButton', () => { + describe('#constructor()', () => { + it('should accept no arguments', () => { + const widget = new ToolbarButton(); + expect(widget).toBeInstanceOf(ToolbarButton); + }); + + it('should accept options', async () => { + const widget = new ToolbarButton({ + className: 'foo', + iconClass: 'iconFoo', + onClick: () => { + return void 0; + }, + tooltip: 'bar' + }); + Widget.attach(widget, document.body); + await framePromise(); + const button = widget.node.firstChild as HTMLElement; + expect(button.classList.contains('foo')).toBe(true); + expect(button.querySelector('.iconFoo')).toBeDefined(); + expect(button.title).toBe('bar'); + }); + }); + + describe('#dispose()', () => { + it('should dispose of the resources used by the widget', () => { + const button = new ToolbarButton(); + button.dispose(); + expect(button.isDisposed).toBe(true); + }); + + it('should be safe to call more than once', () => { + const button = new ToolbarButton(); + button.dispose(); + button.dispose(); + expect(button.isDisposed).toBe(true); + }); + }); + + describe('#handleEvent()', () => { + describe('click', () => { + it('should activate the callback', async () => { + let called = false; + const button = new ToolbarButton({ + onClick: () => { + called = true; + } + }); + Widget.attach(button, document.body); + await framePromise(); + simulate(button.node.firstChild as HTMLElement, 'mousedown'); + expect(called).toBe(true); + button.dispose(); + }); + }); + describe('keydown', () => { + it('Enter should activate the callback', async () => { + let called = false; + const button = new ToolbarButton({ + onClick: () => { + called = true; + } + }); + Widget.attach(button, document.body); + await framePromise(); + simulate(button.node.firstChild as HTMLElement, 'keydown', { + key: 'Enter' + }); + expect(called).toBe(true); + button.dispose(); + }); + it('Space should activate the callback', async () => { + let called = false; + const button = new ToolbarButton({ + onClick: () => { + called = true; + } + }); + Widget.attach(button, document.body); + await framePromise(); + simulate(button.node.firstChild as HTMLElement, 'keydown', { + key: ' ' + }); + expect(called).toBe(true); + button.dispose(); + }); + }); + }); + + describe('#onAfterAttach()', () => { + it.skip('should add event listeners to the node', () => { + // const button = new LogToolbarButton(); + // Widget.attach(button, document.body); + // expect(button.methods).to.contain('onAfterAttach'); + // simulate(button.node, 'click'); + // expect(button.events).to.contain('click'); + // button.dispose(); + }); + }); + + describe('#onBeforeDetach()', () => { + it.skip('should remove event listeners from the node', async () => { + // const button = new LogToolbarButton(); + // Widget.attach(button, document.body); + // await framePromise(); + // Widget.detach(button); + // expect(button.methods).to.contain('onBeforeDetach'); + // simulate(button.node, 'click'); + // expect(button.events).to.not.contain('click'); + // button.dispose(); + }); + }); + + describe('#pressed()', () => { + it('should update the pressed state', async () => { + const widget = new ToolbarButton({ + icon: bugIcon, + tooltip: 'tooltip', + pressedTooltip: 'pressed tooltip', + pressedIcon: bugDotIcon + }); + Widget.attach(widget, document.body); + await framePromise(); + const button = widget.node.firstChild as HTMLElement; + expect(widget.pressed).toBe(false); + expect(button.title).toBe('tooltip'); + expect(button.getAttribute('aria-pressed')).toEqual('false'); + let icon = button.querySelectorAll('svg'); + expect(icon[0].getAttribute('data-icon')).toEqual('ui-components:bug'); + widget.pressed = true; + await framePromise(); + await widget.renderPromise; + expect(widget.pressed).toBe(true); + expect(button.title).toBe('pressed tooltip'); + expect(button.getAttribute('aria-pressed')).toEqual('true'); + icon = button.querySelectorAll('svg'); + expect(icon[0].getAttribute('data-icon')).toEqual( + 'ui-components:bug-dot' + ); + widget.dispose(); + }); + + it('should not have the pressed state when not enabled', async () => { + const widget = new ToolbarButton({ + icon: bugIcon, + tooltip: 'tooltip', + pressedTooltip: 'pressed tooltip', + disabledTooltip: 'disabled tooltip', + pressedIcon: bugDotIcon, + enabled: false + }); + Widget.attach(widget, document.body); + await framePromise(); + const button = widget.node.firstChild as HTMLElement; + expect(widget.pressed).toBe(false); + expect(button.title).toBe('disabled tooltip'); + expect(button.getAttribute('aria-pressed')).toEqual('false'); + widget.pressed = true; + await framePromise(); + expect(widget.pressed).toBe(false); + expect(button.title).toBe('disabled tooltip'); + expect(button.getAttribute('aria-pressed')).toEqual('false'); + const icon = button.querySelectorAll('svg'); + expect(icon[0].getAttribute('data-icon')).toEqual('ui-components:bug'); + widget.dispose(); + }); + }); + + describe('#enabled()', () => { + it('should update the enabled state', async () => { + const widget = new ToolbarButton({ + icon: bugIcon, + tooltip: 'tooltip', + pressedTooltip: 'pressed tooltip', + disabledTooltip: 'disabled tooltip', + pressedIcon: bugDotIcon + }); + Widget.attach(widget, document.body); + await framePromise(); + const button = widget.node.firstChild as HTMLElement; + expect(widget.enabled).toBe(true); + expect(widget.pressed).toBe(false); + expect(button.getAttribute('aria-disabled')).toEqual('false'); + + widget.pressed = true; + await framePromise(); + expect(widget.pressed).toBe(true); + + widget.enabled = false; + await framePromise(); + await widget.renderPromise; + expect(widget.enabled).toBe(false); + expect(widget.pressed).toBe(false); + expect(button.getAttribute('aria-disabled')).toEqual('true'); + widget.dispose(); + }); + }); + + describe('#onClick()', () => { + it('should update the onClick state', async () => { + let mockCalled = false; + const mockOnClick = () => { + mockCalled = true; + }; + const widget = new ToolbarButton({ + icon: bugIcon, + tooltip: 'tooltip', + onClick: mockOnClick + }); + Widget.attach(widget, document.body); + await framePromise(); + simulate(widget.node.firstChild as HTMLElement, 'mousedown'); + expect(mockCalled).toBe(true); + + mockCalled = false; + let mockUpdatedCalled = false; + const mockOnClickUpdated = () => { + mockUpdatedCalled = true; + }; + widget.onClick = mockOnClickUpdated; + await framePromise(); + await widget.renderPromise; + simulate(widget.node.firstChild as HTMLElement, 'mousedown'); + expect(mockCalled).toBe(false); + expect(mockUpdatedCalled).toBe(true); + widget.dispose(); + }); + }); + }); +}); diff --git a/packages/apputils/test/vdom.spec.ts b/packages/ui-components/test/vdom.spec.ts similarity index 89% rename from packages/apputils/test/vdom.spec.ts rename to packages/ui-components/test/vdom.spec.ts index 8c424e6c908e..63002ce74f9d 100644 --- a/packages/apputils/test/vdom.spec.ts +++ b/packages/ui-components/test/vdom.spec.ts @@ -1,8 +1,8 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { VDomModel, VDomRenderer } from '@jupyterlab/apputils'; -import { framePromise } from '@jupyterlab/testutils'; +import { VDomModel, VDomRenderer } from '@jupyterlab/ui-components'; +import { framePromise } from '@jupyterlab/testing'; import { Widget } from '@lumino/widgets'; import * as React from 'react'; @@ -31,7 +31,7 @@ class TestWidgetNoModel extends VDomRenderer { } } -describe('@jupyterlab/apputils', () => { +describe('@jupyterlab/ui-components', () => { describe('VDomModel', () => { describe('#constructor()', () => { it('should create a VDomModel', () => { @@ -79,7 +79,7 @@ describe('@jupyterlab/apputils', () => { }); describe('#modelChanged()', () => { - it('should fire the stateChanged signal on a change', () => { + it('should fire the stateChanged signal on a change', async () => { const model = new TestModel(); const widget = new TestWidget(new TestModel()); let changed = false; @@ -95,9 +95,12 @@ describe('@jupyterlab/apputils', () => { it('should render the contents after a model change', async () => { const widget = new TestWidget(new TestModel()); const model = new TestModel(); + Widget.attach(widget, document.body); widget.model = model; model.value = 'foo'; await framePromise(); + await widget.renderPromise; + await framePromise(); const span = widget.node.firstChild as HTMLElement; expect(span.textContent).toBe('foo'); }); @@ -108,6 +111,7 @@ describe('@jupyterlab/apputils', () => { const widget = new TestWidgetNoModel(); Widget.attach(widget, document.body); await framePromise(); + await widget.renderPromise; const span = widget.node.firstChild as HTMLElement; expect(span.textContent).toBe('No model!'); }); diff --git a/packages/ui-components/tsconfig.json b/packages/ui-components/tsconfig.json index bc2a99db71b5..9d0c4da19d1c 100644 --- a/packages/ui-components/tsconfig.json +++ b/packages/ui-components/tsconfig.json @@ -1,16 +1,22 @@ { "extends": "../../tsconfigbase", "compilerOptions": { - "lib": ["DOM", "ESnext.WeakRef"], + "lib": ["DOM", "DOM.Iterable", "ES2021.WeakRef"], "outDir": "lib", "rootDir": "src", - "types": ["webpack-env", "node"] + "types": ["node"] }, "include": ["src/**/*"], "references": [ { "path": "../coreutils" }, + { + "path": "../observables" + }, + { + "path": "../rendermime-interfaces" + }, { "path": "../translation" } diff --git a/packages/ui-components/tsconfig.test.json b/packages/ui-components/tsconfig.test.json index e07096964a3e..78171285b2bf 100644 --- a/packages/ui-components/tsconfig.test.json +++ b/packages/ui-components/tsconfig.test.json @@ -6,19 +6,19 @@ "path": "../coreutils" }, { - "path": "../translation" + "path": "../observables" }, { - "path": "." + "path": "../rendermime-interfaces" }, { - "path": "../../testutils" + "path": "../translation" }, { - "path": "../coreutils" + "path": "." }, { - "path": "../translation" + "path": "../testing" } ] } diff --git a/packages/vdom-extension/README.md b/packages/vdom-extension/README.md deleted file mode 100644 index f16e532588a8..000000000000 --- a/packages/vdom-extension/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# vdom-extension - -A JupyterLab extension for rendering VirtualDOM using React - -![demo](http://g.recordit.co/EIwAIBsGBh.gif) - -This extension is in the official JupyterLab distribution. - -## Usage - -To render VDOM output in IPython: - -```python -from IPython.display import display - -def VDOM(data={}): - bundle = {} - bundle['application/vdom.v1+json'] = data - display(bundle, raw=True) - -VDOM({ - 'tagName': 'div', - 'attributes': {}, - 'children': [{ - 'tagName': 'h1', - 'attributes': {}, - 'children': 'Our Incredibly Declarative Example', - 'key': 0 - }, { - 'tagName': 'p', - 'attributes': {}, - 'children': ['Can you believe we wrote this ', { - 'tagName': 'b', - 'attributes': {}, - 'children': 'in Python', - 'key': 1 - }, '?'], - 'key': 1 - }, { - 'tagName': 'img', - 'attributes': { - 'src': 'https://media.giphy.com/media/xUPGcguWZHRC2HyBRS/giphy.gif' - }, - 'key': 2 - }, { - 'tagName': 'p', - 'attributes': {}, - 'children': ['What will ', { - 'tagName': 'b', - 'attributes': {}, - 'children': 'you', - 'key': 1 - }, ' create next?'], - 'key': 3 - }] -}) -``` - -Using the [vdom Python library](https://github.com/nteract/vdom): - -```python -from vdom import h1, p, img, div, b - -div( - h1('Our Incredibly Declarative Example'), - p('Can you believe we wrote this ', b('in Python'), '?'), - img(src="https://media.giphy.com/media/xUPGcguWZHRC2HyBRS/giphy.gif"), - p('What will ', b('you'), ' create next?'), -) -``` - -To render a `.vdom` or `.vdom.json` file, simply open it: - -## Development - -See the [JupyterLab Contributor Documentation](https://github.com/jupyterlab/jupyterlab/blob/3.6.x/CONTRIBUTING.md). diff --git a/packages/vdom-extension/package.json b/packages/vdom-extension/package.json deleted file mode 100644 index 052c3b152d96..000000000000 --- a/packages/vdom-extension/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "@jupyterlab/vdom-extension", - "version": "3.6.6", - "description": "JupyterLab - VDOM Renderer", - "homepage": "https://github.com/jupyterlab/jupyterlab", - "bugs": { - "url": "https://github.com/jupyterlab/jupyterlab/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/jupyterlab/jupyterlab.git" - }, - "license": "BSD-3-Clause", - "author": "Project Jupyter", - "sideEffects": [ - "style/**/*" - ], - "main": "lib/index.js", - "types": "lib/index.d.ts", - "style": "style/index.css", - "directories": { - "lib": "lib/" - }, - "files": [ - "lib/*.{d.ts,js,js.map}", - "style/*" - ], - "scripts": { - "build": "tsc -b", - "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", - "docs": "typedoc src", - "watch": "tsc -b --watch" - }, - "dependencies": { - "@jupyterlab/application": "^3.6.6", - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/docregistry": "^3.6.6", - "@jupyterlab/notebook": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/ui-components": "^3.6.6", - "@jupyterlab/vdom": "^3.6.6" - }, - "devDependencies": { - "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" - }, - "publishConfig": { - "access": "public" - }, - "jupyterlab": { - "extension": true - }, - "styleModule": "style/index.js" -} diff --git a/packages/vdom-extension/src/index.ts b/packages/vdom-extension/src/index.ts deleted file mode 100644 index 407bc9c3fb3f..000000000000 --- a/packages/vdom-extension/src/index.ts +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. -/** - * @packageDocumentation - * @module vdom-extension - */ - -import { - ILayoutRestorer, - JupyterFrontEnd, - JupyterFrontEndPlugin -} from '@jupyterlab/application'; -import { WidgetTracker } from '@jupyterlab/apputils'; -import { MimeDocument, MimeDocumentFactory } from '@jupyterlab/docregistry'; -import { INotebookTracker } from '@jupyterlab/notebook'; -import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; -import { reactIcon } from '@jupyterlab/ui-components'; -import { IVDOMTracker, RenderedVDOM } from '@jupyterlab/vdom'; - -/** - * The MIME type for VDOM. - */ -export const MIME_TYPE = 'application/vdom.v1+json'; - -/** - * The name of the factory that creates VDOM widgets. - */ -const FACTORY_NAME = 'VDOM'; - -const plugin: JupyterFrontEndPlugin = { - id: '@jupyterlab/vdom-extension:factory', - requires: [IRenderMimeRegistry], - optional: [INotebookTracker, ILayoutRestorer], - provides: IVDOMTracker, - autoStart: true, - activate: ( - app: JupyterFrontEnd, - rendermime: IRenderMimeRegistry, - notebooks: INotebookTracker | null, - restorer: ILayoutRestorer | null - ) => { - const tracker = new WidgetTracker({ - namespace: 'vdom-widget' - }); - - // Add a renderer factory to application rendermime registry. - rendermime.addFactory( - { - safe: false, - mimeTypes: [MIME_TYPE], - createRenderer: options => new RenderedVDOM(options) - }, - 0 - ); - - if (notebooks) { - notebooks.widgetAdded.connect((sender, panel) => { - // Get the notebook's context and rendermime; - const { - context, - content: { rendermime } - } = panel; - - // Add the renderer factory to the notebook's rendermime registry; - rendermime.addFactory( - { - safe: false, - mimeTypes: [MIME_TYPE], - createRenderer: options => new RenderedVDOM(options, context) - }, - 0 - ); - }); - } - - app.docRegistry.addFileType({ - name: 'vdom', - mimeTypes: [MIME_TYPE], - extensions: ['.vdom', '.vdom.json'], - icon: reactIcon - }); - - const factory = new MimeDocumentFactory({ - renderTimeout: 1000, - dataType: 'json', - rendermime, - name: FACTORY_NAME, - primaryFileType: app.docRegistry.getFileType('vdom')!, - fileTypes: ['vdom', 'json'], - defaultFor: ['vdom'] - }); - - factory.widgetCreated.connect((sender, widget) => { - widget.context.pathChanged.connect(() => { - void tracker.save(widget); - }); - void tracker.add(widget); - }); - - // Add widget factory to document registry. - app.docRegistry.addWidgetFactory(factory); - - if (restorer) { - // Handle state restoration. - void restorer.restore(tracker, { - command: 'docmanager:open', - args: widget => ({ - path: widget.context.path, - factory: FACTORY_NAME - }), - name: widget => widget.context.path - }); - } - - return tracker; - } -}; - -export default plugin; diff --git a/packages/vdom-extension/typedoc.json b/packages/vdom-extension/typedoc.json deleted file mode 100644 index 1c5fb0045904..000000000000 --- a/packages/vdom-extension/typedoc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "out": "../../docs/api/vdom-extension", - "theme": "../../typedoc-theme" -} diff --git a/packages/vdom/README.md b/packages/vdom/README.md deleted file mode 100644 index e7f2042c4ab1..000000000000 --- a/packages/vdom/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# vdom - -A library for rendering VirtualDOM content using React. - -## Development - -See the [JupyterLab Contributor Documentation](https://github.com/jupyterlab/jupyterlab/blob/3.6.x/CONTRIBUTING.md). diff --git a/packages/vdom/package.json b/packages/vdom/package.json deleted file mode 100644 index b4e99584299f..000000000000 --- a/packages/vdom/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "@jupyterlab/vdom", - "version": "3.6.6", - "description": "A viewer for VDOM documents.", - "homepage": "https://github.com/jupyterlab/jupyterlab", - "bugs": { - "url": "https://github.com/jupyterlab/jupyterlab/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/jupyterlab/jupyterlab.git" - }, - "license": "BSD-3-Clause", - "author": "Project Jupyter", - "sideEffects": [ - "style/**/*" - ], - "main": "lib/index.js", - "types": "lib/index.d.ts", - "style": "style/index.css", - "directories": { - "lib": "lib/" - }, - "files": [ - "lib/*.{d.ts,js,js.map}", - "style/*" - ], - "scripts": { - "build": "tsc -b", - "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", - "docs": "typedoc src", - "watch": "tsc -b --watch" - }, - "dependencies": { - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/docregistry": "^3.6.6", - "@jupyterlab/rendermime-interfaces": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@lumino/coreutils": "^1.11.0", - "@lumino/messaging": "^1.10.0", - "@lumino/widgets": "^1.37.2", - "@nteract/transform-vdom": "^4.0.16-alpha.0", - "react": "^17.0.1", - "react-dom": "^17.0.1" - }, - "devDependencies": { - "@types/react": "^17.0.0", - "@types/react-dom": "^17.0.0", - "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" - }, - "publishConfig": { - "access": "public" - }, - "styleModule": "style/index.js" -} diff --git a/packages/vdom/src/index.tsx b/packages/vdom/src/index.tsx deleted file mode 100644 index 79b03d97c626..000000000000 --- a/packages/vdom/src/index.tsx +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. -/** - * @packageDocumentation - * @module vdom - */ - -import { ISessionContext, IWidgetTracker } from '@jupyterlab/apputils'; -import { DocumentRegistry, MimeDocument } from '@jupyterlab/docregistry'; -import { IRenderMime } from '@jupyterlab/rendermime-interfaces'; -import { Kernel } from '@jupyterlab/services'; -import { Token } from '@lumino/coreutils'; -import { Message } from '@lumino/messaging'; -import { Widget } from '@lumino/widgets'; -import VDOM, { SerializedEvent } from '@nteract/transform-vdom'; -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; - -/** - * The CSS class to add to the VDOM Widget. - */ -const CSS_CLASS = 'jp-RenderedVDOM'; - -/** - * A class that tracks VDOM widgets. - */ -export interface IVDOMTracker extends IWidgetTracker {} - -/** - * The VDOM tracker token. - */ -export const IVDOMTracker = new Token( - '@jupyterlab/vdom:IVDOMTracker' -); - -/** - * A renderer for declarative virtual DOM content. - */ -export class RenderedVDOM extends Widget implements IRenderMime.IRenderer { - /** - * Create a new widget for rendering DOM. - */ - constructor( - options: IRenderMime.IRendererOptions, - context?: DocumentRegistry.IContext - ) { - super(); - this.addClass(CSS_CLASS); - this.addClass('jp-RenderedHTML'); - this.addClass('jp-RenderedHTMLCommon'); - this._mimeType = options.mimeType; - if (context) { - this._sessionContext = context.sessionContext; - } - } - - /** - * Dispose of the widget. - */ - dispose(): void { - // Dispose of comm disposables - for (const targetName in this._comms) { - this._comms[targetName].dispose(); - } - super.dispose(); - } - - /** - * Called before the widget is detached from the DOM. - */ - protected onBeforeDetach(msg: Message): void { - // Dispose of React component(s). - ReactDOM.unmountComponentAtNode(this.node); - } - - /** - * Render VDOM into this widget's node. - */ - renderModel(model: IRenderMime.IMimeModel): Promise { - return new Promise((resolve, reject) => { - const data = model.data[this._mimeType] as any; - ReactDOM.render( - , - this.node, - () => { - resolve(); - } - ); - }); - } - - /** - * Handle events for VDOM element. - */ - handleVDOMEvent = (targetName: string, event: SerializedEvent): void => { - // When a VDOM element's event handler is called, send a serialized - // representation of the event to the registered comm channel for the - // kernel to handle - if (this._timer) { - window.clearTimeout(this._timer); - } - const kernel = this._sessionContext?.session?.kernel; - if (kernel) { - this._timer = window.setTimeout(() => { - if (!this._comms[targetName]) { - this._comms[targetName] = kernel.createComm(targetName); - this._comms[targetName].open(); - } - this._comms[targetName].send(JSON.stringify(event)); - }, 16); - } - }; - - private _mimeType: string; - private _sessionContext?: ISessionContext; - private _comms: { [targetName: string]: Kernel.IComm } = {}; - private _timer: number; -} diff --git a/packages/vdom/style/base.css b/packages/vdom/style/base.css deleted file mode 100644 index 850eccd402f0..000000000000 --- a/packages/vdom/style/base.css +++ /dev/null @@ -1,17 +0,0 @@ -/** - Copyright (c) Jupyter Development Team. - Distributed under the terms of the Modified BSD License. -*/ - -/* Base styles */ -.jp-RenderedVDOM { - width: 100%; - height: 100%; - padding: 0; - overflow: auto; -} - -/* Document styles */ -.jp-MimeDocument .jp-RenderedVDOM { - padding: 5px; -} diff --git a/packages/vdom/tsconfig.json b/packages/vdom/tsconfig.json deleted file mode 100644 index d98fff4ce7b3..000000000000 --- a/packages/vdom/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../tsconfigbase", - "compilerOptions": { - "outDir": "lib", - "rootDir": "src" - }, - "include": ["src/*"], - "references": [ - { - "path": "../apputils" - }, - { - "path": "../docregistry" - }, - { - "path": "../rendermime-interfaces" - }, - { - "path": "../services" - } - ] -} diff --git a/packages/vdom/typedoc.json b/packages/vdom/typedoc.json deleted file mode 100644 index 4c6faa6b2b95..000000000000 --- a/packages/vdom/typedoc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "out": "../../docs/api/vdom", - "theme": "../../typedoc-theme" -} diff --git a/packages/vega5-extension/README.md b/packages/vega5-extension/README.md index ca9b9edc2986..de8dbc9e3a25 100644 --- a/packages/vega5-extension/README.md +++ b/packages/vega5-extension/README.md @@ -102,4 +102,4 @@ To render a `.vl`, `.vg`, `vl.json` or `.vg.json` file, simply open it: ## Development -See the [JupyterLab Contributor Documentation](https://github.com/jupyterlab/jupyterlab/blob/3.6.x/CONTRIBUTING.md). +See the [JupyterLab Contributor Documentation](https://github.com/jupyterlab/jupyterlab/blob/4.0.x/CONTRIBUTING.md). diff --git a/packages/vega5-extension/package.json b/packages/vega5-extension/package.json index 5f244531df71..06af3aab595b 100644 --- a/packages/vega5-extension/package.json +++ b/packages/vega5-extension/package.json @@ -1,7 +1,7 @@ { "name": "@jupyterlab/vega5-extension", - "version": "3.6.6", - "description": "JupyterLab - Vega 5 and Vega-Lite 3 Mime Renderer Extension", + "version": "4.0.8", + "description": "JupyterLab - Vega 5 and Vega-Lite 5 Mime Renderer Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { "url": "https://github.com/jupyterlab/jupyterlab/issues" @@ -23,7 +23,8 @@ }, "files": [ "lib/*.{d.ts,js,js.map}", - "style/*.*" + "style/*.*", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", @@ -32,26 +33,26 @@ "docs": "typedoc src", "test": "jest", "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", + "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand", + "test:debug:watch": "node --inspect-brk ../../node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/rendermime-interfaces": "^3.6.6", - "@lumino/coreutils": "^1.11.0", - "@lumino/widgets": "^1.37.2", + "@jupyterlab/rendermime-interfaces": "^3.8.8", + "@lumino/coreutils": "^2.1.2", + "@lumino/widgets": "^2.3.0", "vega": "^5.20.0", "vega-embed": "^6.2.1", - "vega-lite": "^5.1.0" + "vega-lite": "^5.6.1-next.1" }, "devDependencies": { - "@jupyterlab/testutils": "^3.6.6", - "@types/jest": "^26.0.10", - "@types/webpack-env": "^1.14.1", - "jest": "^26.4.2", + "@jupyterlab/testutils": "^4.0.8", + "@types/jest": "^29.2.0", + "@types/webpack-env": "^1.18.0", + "jest": "^29.2.0", "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.24.7", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/vega5-extension/src/index.ts b/packages/vega5-extension/src/index.ts index 1a3369389c7e..35a87e997427 100644 --- a/packages/vega5-extension/src/index.ts +++ b/packages/vega5-extension/src/index.ts @@ -51,6 +51,14 @@ export const VEGALITE3_MIME_TYPE = 'application/vnd.vegalite.v3+json'; */ export const VEGALITE4_MIME_TYPE = 'application/vnd.vegalite.v4+json'; +/** + * The MIME type for Vega-Lite. + * + * #### Notes + * The version of this follows the major version of Vega-Lite. + */ +export const VEGALITE5_MIME_TYPE = 'application/vnd.vegalite.v5+json'; + /** * A widget for rendering Vega or Vega-Lite data, for usage with rendermime. */ @@ -136,7 +144,11 @@ export class RenderedVega extends Widget implements IRenderMime.IRenderer { // Add png representation of vega chart to output const imageURL = await this._result.view.toImageURL( 'png', - embedOptions.scaleFactor + typeof embedOptions.scaleFactor === 'number' + ? embedOptions.scaleFactor + : embedOptions.scaleFactor + ? (embedOptions.scaleFactor as any).png + : embedOptions.scaleFactor ); model.setData({ data: { ...model.data, 'image/png': imageURL.split(',')[1] } @@ -159,12 +171,18 @@ export class RenderedVega extends Widget implements IRenderMime.IRenderer { */ export const rendererFactory: IRenderMime.IRendererFactory = { safe: true, - mimeTypes: [VEGA_MIME_TYPE, VEGALITE3_MIME_TYPE, VEGALITE4_MIME_TYPE], + mimeTypes: [ + VEGA_MIME_TYPE, + VEGALITE3_MIME_TYPE, + VEGALITE4_MIME_TYPE, + VEGALITE5_MIME_TYPE + ], createRenderer: options => new RenderedVega(options) }; const extension: IRenderMime.IExtension = { id: '@jupyterlab/vega5-extension:factory', + description: 'Provides a renderer for Vega 5 and Vega-Lite 3 to 5 content.', rendererFactory, rank: 57, dataType: 'json', @@ -176,10 +194,10 @@ const extension: IRenderMime.IExtension = { defaultFor: ['vega5'] }, { - name: 'Vega-Lite4', - primaryFileType: 'vega-lite4', - fileTypes: ['vega-lite3', 'vega-lite4', 'json'], - defaultFor: ['vega-lite3', 'vega-lite4'] + name: 'Vega-Lite5', + primaryFileType: 'vega-lite5', + fileTypes: ['vega-lite3', 'vega-lite4', 'vega-lite5', 'json'], + defaultFor: ['vega-lite3', 'vega-lite4', 'vega-lite5'] } ], fileTypes: [ @@ -189,10 +207,16 @@ const extension: IRenderMime.IExtension = { extensions: ['.vg', '.vg.json', '.vega'], icon: 'ui-components:vega' }, + { + mimeTypes: [VEGALITE5_MIME_TYPE], + name: 'vega-lite5', + extensions: ['.vl', '.vl.json', '.vegalite'], + icon: 'ui-components:vega' + }, { mimeTypes: [VEGALITE4_MIME_TYPE], name: 'vega-lite4', - extensions: ['.vl', '.vl.json', '.vegalite'], + extensions: [], icon: 'ui-components:vega' }, { diff --git a/packages/vega5-extension/src/json.d.ts b/packages/vega5-extension/src/json.d.ts index 3abbcd236bbf..8413bca0d1e3 100644 --- a/packages/vega5-extension/src/json.d.ts +++ b/packages/vega5-extension/src/json.d.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + declare module '*.json' { export const version: string; } diff --git a/packages/vega5-extension/style/index.css b/packages/vega5-extension/style/index.css index 8fe68ab59e76..175c3e71145f 100644 --- a/packages/vega5-extension/style/index.css +++ b/packages/vega5-extension/style/index.css @@ -5,5 +5,4 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ @import url('~@lumino/widgets/style/index.css'); - @import url('./base.css'); diff --git a/packages/vega5-extension/test/renderer.spec.ts b/packages/vega5-extension/test/renderer.spec.ts index 570cba310aed..349953ce606f 100644 --- a/packages/vega5-extension/test/renderer.spec.ts +++ b/packages/vega5-extension/test/renderer.spec.ts @@ -2,13 +2,13 @@ // Distributed under the terms of the Modified BSD License. import { MimeModel } from '@jupyterlab/rendermime'; -import { VEGALITE4_MIME_TYPE } from '@jupyterlab/vega5-extension'; +import { VEGALITE5_MIME_TYPE } from '@jupyterlab/vega5-extension'; import { DEFAULT_SIZE, getPNGSize, SCALE_FACTOR_PROP, - VEGALITE4_RENDERER, - VEGALITE4_SPEC + VEGALITE5_RENDERER, + VEGALITE5_SPEC } from './utils'; describe('@jupyterlab/vega5-extension', () => { @@ -16,10 +16,10 @@ describe('@jupyterlab/vega5-extension', () => { it('should attach a default sized PNG', async () => { const model = new MimeModel({ data: { - [VEGALITE4_MIME_TYPE]: VEGALITE4_SPEC + [VEGALITE5_MIME_TYPE]: VEGALITE5_SPEC } }); - await VEGALITE4_RENDERER.renderModel(model); + await VEGALITE5_RENDERER.renderModel(model); expect(model).toHaveProperty('data.image/png'); expect(model).not.toHaveProperty(SCALE_FACTOR_PROP); @@ -35,17 +35,17 @@ describe('@jupyterlab/vega5-extension', () => { const model = new MimeModel({ data: { - [VEGALITE4_MIME_TYPE]: VEGALITE4_SPEC + [VEGALITE5_MIME_TYPE]: VEGALITE5_SPEC }, metadata: { - [VEGALITE4_MIME_TYPE]: { + [VEGALITE5_MIME_TYPE]: { embed_options: { scaleFactor } } } }); - await VEGALITE4_RENDERER.renderModel(model); + await VEGALITE5_RENDERER.renderModel(model); expect(model).toHaveProperty('data.image/png'); expect(model).toHaveProperty(SCALE_FACTOR_PROP, scaleFactor); diff --git a/packages/vega5-extension/test/utils.ts b/packages/vega5-extension/test/utils.ts index 07fb1dc545e1..81f2a6d41064 100644 --- a/packages/vega5-extension/test/utils.ts +++ b/packages/vega5-extension/test/utils.ts @@ -3,7 +3,7 @@ * Distributed under the terms of the Modified BSD License. */ -import { RenderedVega, VEGALITE4_MIME_TYPE } from '@jupyterlab/vega5-extension'; +import { RenderedVega, VEGALITE5_MIME_TYPE } from '@jupyterlab/vega5-extension'; import { JSONObject } from '@lumino/coreutils'; interface ISize { @@ -14,23 +14,23 @@ interface ISize { export const DEFAULT_SIZE: number = 200; export const SCALE_FACTOR_PROP: string[] = [ 'metadata', - VEGALITE4_MIME_TYPE, + VEGALITE5_MIME_TYPE, 'embed_options', 'scaleFactor' ]; -export const VEGALITE4_RENDERER = new RenderedVega({ +export const VEGALITE5_RENDERER = new RenderedVega({ latexTypesetter: null, linkHandler: null, - mimeType: VEGALITE4_MIME_TYPE, + mimeType: VEGALITE5_MIME_TYPE, resolver: null, sanitizer: { sanitize: (s: string) => s } }); -export const VEGALITE4_SPEC: JSONObject = { - $schema: 'https://vega.github.io/schema/vega-lite/v4.json', +export const VEGALITE5_SPEC: JSONObject = { + $schema: 'https://vega.github.io/schema/vega-lite/v5.json', description: 'A simple bar chart with embedded data.', width: DEFAULT_SIZE, height: DEFAULT_SIZE, diff --git a/packages/vega5-extension/tsconfig.json b/packages/vega5-extension/tsconfig.json index a631202393b1..68df27709c47 100644 --- a/packages/vega5-extension/tsconfig.json +++ b/packages/vega5-extension/tsconfig.json @@ -2,7 +2,6 @@ "extends": "../../tsconfigbase", "compilerOptions": { "outDir": "lib", - "skipLibCheck": true, "types": ["webpack-env"], "rootDir": "src" }, diff --git a/packages/vega5-extension/tsconfig.test.json b/packages/vega5-extension/tsconfig.test.json index 55cd5071c944..f42577169fda 100644 --- a/packages/vega5-extension/tsconfig.test.json +++ b/packages/vega5-extension/tsconfig.test.json @@ -10,9 +10,6 @@ }, { "path": "../../testutils" - }, - { - "path": "../rendermime-interfaces" } ] } diff --git a/pyproject.toml b/pyproject.toml index 86b65c41e6b8..458ffe4fd091 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,39 +1,321 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + [build-system] -requires=["jupyter_packaging>=0.9,<2"] -build-backend = "jupyter_packaging.build_api" +requires = ["hatchling>=1.5.0"] +build-backend = "hatchling.build" + +[project] +name = "jupyterlab" +description = "JupyterLab computational environment" +readme = "README.md" +license = { file = "LICENSE" } +requires-python = ">=3.8" +authors = [ + { name = "Jupyter Development Team", email = "jupyter@googlegroups.com" }, +] +keywords = [ + "ipython", + "jupyter", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Framework :: Jupyter", + "Framework :: Jupyter :: JupyterLab", + "Framework :: Jupyter :: JupyterLab :: 4", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +dependencies = [ + "async_lru>=1.0.0", + "importlib-metadata>=4.8.3;python_version<\"3.10\"", + "importlib-resources>=1.4;python_version<\"3.9\"", + "ipykernel", + "jinja2>=3.0.3", + "jupyter_core", + "jupyter-lsp>=2.0.0", + "jupyter_server>=2.4.0,<3", + "jupyterlab_server>=2.19.0,<3", + "notebook_shim>=0.2", + "packaging", + "traitlets", + "tornado>=6.2.0", + "tomli;python_version<\"3.11\"", +] +dynamic = [ + "version", +] + +[project.scripts] +jlpm = "jupyterlab.jlpmapp:main" +jupyter-lab = "jupyterlab.labapp:main" +jupyter-labextension = "jupyterlab.labextensions:main" +jupyter-labhub = "jupyterlab.labhubapp:main" + +[project.entry-points."jupyterlab.extension_manager_v1"] +readonly = "jupyterlab.extensions:get_readonly_manager" +pypi = "jupyterlab.extensions:get_pypi_manager" + +[project.urls] +Homepage = "https://jupyter.org" +Changelog = "https://jupyterlab.readthedocs.io/en/stable/getting_started/changelog.html" +Documentation = "https://jupyterlab.readthedocs.io" +Source = "https://github.com/jupyterlab/jupyterlab" +Issues = "https://github.com/jupyterlab/jupyterlab/issues/new/choose" +Gitter = "https://gitter.im/jupyterlab/jupyterlab" +Pypi = "https://pypi.org/project/jupyterlab" + +[project.optional-dependencies] +docs = [ + "sphinx>=1.8,<7.2.0", + "sphinx-copybutton", + "pydata-sphinx-theme>=0.13.0", + "pytest", + "pytest-tornasync", + "pytest-check-links", + "jsx-lexer", + "myst-parser", +] +docs-screenshots = [ + "altair==5.0.1", + "ipython==8.14.0", + "ipywidgets==8.0.6", + "jupyterlab-geojson==3.4.0", + "jupyterlab-language-pack-zh-CN==4.0.post0", + "matplotlib==3.7.1", + "nbconvert>=7.0.0", + "pandas==2.0.2", + "scipy==1.10.1", + "vega_datasets==0.9.0", +] +test = [ + "coverage", + "pytest>=7.0", + "pytest-check-links>=0.7", + "pytest-console-scripts", + "pytest-cov", + "pytest-jupyter>=0.5.3", + "pytest-timeout", + "pytest-tornasync", + "requests", + "requests_cache", + "virtualenv", +] +dev = [ + "build", + "pre-commit", + "pytest-cov", + "coverage", + "hatch", + "bump2version", + "ruff==0.0.292", + "black[jupyter]==23.10.1" +] + +[tool.check-wheel-contents] +ignore = ["W002", "W004"] + +[tool.hatch.version] +path = "jupyterlab/_version.py" +source = "code" -[license] -file="LICENSE" +[tool.hatch.build.targets.wheel.shared-data] +"jupyterlab/static" = "share/jupyter/lab/static" +"jupyterlab/schemas" = "share/jupyter/lab/schemas" +"jupyterlab/themes" = "share/jupyter/lab/themes" +"jupyter-config" = "etc/jupyter" +"jupyterlab.svg" = "share/icons/hicolor/scalable/apps/jupyterlab.svg" +"jupyterlab.desktop" = "share/applications/jupyterlab.desktop" -[tool.jupyter-packaging.builder] -factory = "jupyter_packaging.npm_builder" +[tool.hatch.build] +ignore-vcs = true -[tool.jupyter-packaging.build-args] +[tool.hatch.build.targets.sdist] +include = [ + "/*.md", + "/buildapi.py", + "/conftest.py", + "/docs", + "/docker", + "/Dockerfile", + "/.dockerignore", + "/galata", + "/jupyter-config", + "/jupyterlab", + "/package.json", + "jupyterlab.svg", + "jupyterlab.desktop" +] +exclude = [ + "/.github", + "*.js.map", + "node_modules", + "/clean.py", + "/binder", + "/builder", + "/buildutils", + "/dist", + "/docs/build", + "/docs/source/api", + "/design", + "/dev_mode", + "/examples", + "/galata/lib", + "/jupyterlab/staging/build", + "/jupyterlab/staging/.yarn", + "/packages", + "/release", + "/testutils", + "/typedoc-theme" +] + +[tool.hatch.build.targets.wheel] +include = [ + "/jupyterlab", +] +exclude = [ + "*.js.map", + "/jupyterlab/staging/build", + "/jupyterlab/staging/.yarn", + "node_modules" +] + +[tool.hatch.build.hooks.jupyter-builder] +dependencies = ["hatch-jupyter-builder>=0.3.2"] +build-function = "buildapi.builder" +ensured-targets = [ + "jupyterlab/static/package.json", + "jupyterlab/schemas/@jupyterlab/shortcuts-extension/shortcuts.json", + "jupyterlab/themes/@jupyterlab/theme-light-extension/index.css" +] +install-pre-commit-hook = true + +[tool.hatch.build.hooks.jupyter-builder.editable-build-kwargs] +build_cmd = "build" +source_dir = "packages" +build_dir = "dev_mode/static" +npm = ["node", "jupyterlab/staging/yarn.js"] + +[tool.hatch.build.hooks.jupyter-builder.build-kwargs] build_cmd = "build:prod:minimize" path = "jupyterlab/staging" -source_dir= "jupyterlab/staging" +source_dir = "jupyterlab/staging" build_dir = "jupyterlab/static" npm = ["node", "yarn.js"] [tool.pytest.ini_options] -testpaths="jupyterlab/tests" -norecursedirs="node_modules .git _build" -addopts="--pdbcls=IPython.terminal.debugger:Pdb -v --junitxml=junit.xml" -ignore="tests examples" - -[tool.check-manifest] -ignore = ["binder/**", "builder/**", "buildutils/**", "design/**", "dev_mode/**", "examples/**", "packages/**", "scripts/**", "testutils/**", "*.json", "yarn.lock", "readthedocs.yml", ".bumpversion.cfg", ".*", "clean.py", "*.config.js", "release/*", "typedoc-theme/**", "typedoc.js", "jupyterlab/schemas/**", "jupyterlab/static/**", "jupyterlab/themes/**", "jupyterlab/style.js"] +testpaths = "jupyterlab/tests" +norecursedirs = "node_modules .git _build" +addopts = "--pdbcls=IPython.terminal.debugger:Pdb -v --junitxml=junit.xml" +ignore = "tests examples" [tool.jupyter-releaser.options] version-cmd = "jlpm bumpversion --force --skip-commit" npm-install-options = "--legacy-peer-deps" npm-cmd = "npm publish --tag latest" -pydist-extra-check-cmds = "" release-message = "[ci skip] Publish {version}" tag-message = "[ci skip] Release {tag_name}" [tool.jupyter-releaser.hooks] -before-bump-version = ["pip install -e .[test]"] -before-build-npm = ["jlpm", "jlpm run build:all"] -before-build-python = ["node buildutils/lib/local-repository start; true", "jlpm run before:build:python", "node buildutils/lib/local-repository stop", "node buildutils/lib/local-repository fix-links --path jupyterlab/staging"] +before-bump-version = [ + "pip install -e .[dev]", + "git checkout .", +] +before-build-npm = [ + "jlpm", + "jlpm run build:all", +] +before-build-python = [ + "node buildutils/lib/local-repository start", + "jlpm run before:build:python", + "node buildutils/lib/local-repository stop", +] after-publish-assets = "npm run after:publish:assets" + +[tool.black] +line-length = 100 +target-version = ["py37"] +skip-string-normalization = true +extend-exclude = ''' +( + .*\/css_js_injection.ipynb # Exclude integration test notebook +) +''' + +[tool.ruff] +target-version = "py37" +line-length = 100 +select = [ + "A", "B", "C", "DTZ", "E", "EM", "F", "FBT", "I", "ICN", "ISC", "N", + "PLC", "PLE", "PLR", "PLW", "Q", "RUF", "S", "SIM", "T", "TID", "UP", + "W", "YTT", +] +ignore = [ +# Q000 Single quotes found but double quotes preferred +"Q000", +# FBT001 Boolean positional arg in function definition +"FBT001", "FBT002", "FBT003", +# E501 Line too long (158 > 100 characters) +"E501", +# PLR0913 Too many arguments to function call +"PLR0913", +# SIM105 Use `contextlib.suppress(...)` +"SIM105", +] + +[tool.ruff.per-file-ignores] +# F821 Undefined name `c` +"binder/jupyter_config.py" = ["F821"] +# RUF012 Mutable class attributes should be annotated with `typing.ClassVar` +"examples/example_check.py" = ["RUF012"] +# RUF012 Mutable class attributes should be annotated with `typing.ClassVar` +"examples/federated/main.py" = ["RUF012"] +# T201 `print` found +"examples/test_examples.py" = ["T201"] +# T201 `print` found +"galata/*" = ["T201"] +# F821 Undefined name `c` +# S104 Possible binding to all interfaces +# S105 Possible hardcoded password: `""` +"galata/jupyter_server_test_config.py" = ["F821", "S104", "S105"] +# T201 `print` found +"jupyterlab/browser_check.py" = ["RUF012", "T201"] +# C901 method is too complex +"jupyterlab/commands.py" = ["C901"] +# B028 No explicit `stacklevel` keyword argument found +"jupyterlab/debuglog.py" = ["B028"] +"jupyterlab/extensions/manager.py" = ["C901"] +# RUF012 Mutable class attributes should be annotated with `typing.ClassVar` +# T201 `print` found +"jupyterlab/labapp.py" = ["RUF012", "T201"] +# RUF012 Mutable class attributes should be annotated with `typing.ClassVar` +"jupyterlab/labextensions.py" = ["RUF012"] +# C901 method is too complex +# S101 Use of `assert` detected +# N802 Function name `foo` should be lowercase +# EM101 Exception must not use a string literal +# PLR2004 Magic value used in comparison +"jupyterlab/tests/*" = ["C901", "S101", "N802", "E501", "EM101", "EM102", "EM103", "PLR2004"] +# RUF012 Mutable class attributes should be annotated with `typing.ClassVar` +"jupyterlab/tests/echo_kernel.py" = ["RUF012"] +# T201 `print` found +"scripts/milestone_check.py" = ["T201"] +# N806 Variable `tM` in function should be lowercase +# N816 Variable `comparatorTrimReplace` in global scope should not be mixedCase +# PLC1901 test can be simplified as an empty string is falsey +# PLR1714 Consider merging multiple comparisons +# PLR5501 Use `elif` instead of `else` then `if`, to reduce indentation +"jupyterlab/semver.py" = ["C901", "EM101", "EM102", "N806", "N816", "PLC1901", "PLR1714", "PLR5501"] +# T201 `print` found +"jupyterlab/upgrade_extension.py" = ["T201"] +# RUF012 Mutable class attributes should be annotated with `typing.ClassVar` +"packages/services/examples/node/main.py" = ["RUF012"] +# T201 `print` found +"scripts/i18n_check.py" = ["T201"] diff --git a/release/Dockerfile b/release/Dockerfile deleted file mode 100644 index d5f21df3bc1b..000000000000 --- a/release/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM python:3 - -WORKDIR /usr/src/app - -ARG GIT_AUTHOR_NAME -ARG GIT_AUTHOR_EMAIL - -ENV GIT_AUTHOR_NAME=$GIT_AUTHOR_NAME -ENV GIT_AUTHOR_EMAIL=$GIT_AUTHOR_EMAIL - -RUN git config --global user.name "$GIT_AUTHOR_NAME" -RUN git config --global user.email "$GIT_AUTHOR_EMAIL" - -RUN apt-get update && apt-get install -y npm twine - -CMD ["bash"] diff --git a/scripts/build_docker.sh b/scripts/build_docker.sh deleted file mode 100755 index b4884685bc98..000000000000 --- a/scripts/build_docker.sh +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/sh -# This script build the JupyterLab image -if [ -d ${PWD}/packages ]; then - echo Create package.json files archive - tar cf /tmp/package_json.tar.gz package.json packages/*/package.json - cp /tmp/package_json.tar.gz ${PWD} - echo Build JupyterLab docker - docker build -f Dockerfile -t jupyterlab-dev ${PWD} -else - echo You need to run this script from the JupyterLab root folder -fi \ No newline at end of file diff --git a/scripts/ci_install.ps1 b/scripts/ci_install.ps1 index 53770ca7d0e7..f2c1b6d0aae7 100644 --- a/scripts/ci_install.ps1 +++ b/scripts/ci_install.ps1 @@ -1,7 +1,8 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -$ErrorActionPreference = 'stop' +$Env:YARN_ENABLE_GLOBAL_CACHE = "1" +$ErrorActionPreference = "stop" # create jupyter base dir (needed for config retrieval) New-Item -Path $Env:USERPROFILE\.jupyter -ItemType "directory" -Force @@ -14,13 +15,16 @@ pip --version if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } # Show a verbose install if the install fails, for debugging -pip install -e ".[test]" || pip install -v -e ".[test]" +pip install -e ".[dev,test]" || pip install -v -e ".[dev,test]" if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } -jlpm versions +# next two lines equivalent to deprecated `yarn versions` cmd from yarn@1.x +jlpm --version +jlpm node -p process.versions if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } -jlpm config current +# print current yarn config info +jlpm config if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } jupyter lab path @@ -30,14 +34,4 @@ jupyter server extension enable jupyterlab if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } # TODO: batch script grepping -# TODO: remove when we no longer support classic notebook -jupyter serverextension enable jupyterlab -if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } -# TODO: batch script grepping - -if ($Env:GROUP -eq "integrity") { - pip install notebook==4.3.1 - if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } -} - if ((Test-Path -LiteralPath variable:\LASTEXITCODE)) { exit $LASTEXITCODE } diff --git a/scripts/ci_install.sh b/scripts/ci_install.sh index f3e6a1acb661..e53e1943fd6e 100755 --- a/scripts/ci_install.sh +++ b/scripts/ci_install.sh @@ -5,6 +5,13 @@ set -ex set -o pipefail +# use a single global cache dir +export YARN_ENABLE_GLOBAL_CACHE=1 + +# display verbose output for pkg builds run during `jlpm install` +export YARN_ENABLE_INLINE_BUILDS=1 + + # Building should work without yarn installed globally, so uninstall the # global yarn installed by default. if [ $OSTYPE == "Linux" ]; then @@ -23,21 +30,10 @@ git config --global user.email foo@bar.com pip install -q --upgrade pip --user pip --version # Show a verbose install if the install fails, for debugging -pip install -e ".[test]" || pip install -v -e ".[test]" -jlpm versions -jlpm config current - -# TODO: remove when we no longer support classic notebook -jupyter serverextension enable jupyterlab -jupyter serverextension list 1>serverextensions 2>&1 -cat serverextensions -cat serverextensions | grep -i "jupyterlab.*enabled" -cat serverextensions | grep -i "jupyterlab.*OK" -rm serverextensions - -if [[ $GROUP == integrity ]]; then - pip install notebook==4.3.1 -fi +pip install -e ".[dev,test]" || pip install -v -e ".[dev,test]" +yarn --version +node -p process.versions +jlpm config if [[ $GROUP == nonode ]]; then # Build the wheel diff --git a/scripts/ci_script.ps1 b/scripts/ci_script.ps1 index df8ae3b015e9..feec93b500a6 100644 --- a/scripts/ci_script.ps1 +++ b/scripts/ci_script.ps1 @@ -1,14 +1,20 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -$ErrorActionPreference = 'stop' +$Env:YARN_ENABLE_GLOBAL_CACHE = "1" +$ErrorActionPreference = "stop" python -c "from jupyterlab.commands import build_check; build_check()" if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } if ($Env:GROUP -eq "python") { + $Env:JUPYTERLAB_DIR = "$Env:HOME/share/jupyter/lab/" + mkdir $Env:JUPYTERLAB_DIR -ea 0 + + $Env:YARN_ENABLE_IMMUTABLE_INSTALLS = 1 jupyter lab build --debug if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } + Remove-Item Env:\YARN_ENABLE_IMMUTABLE_INSTALLS # Run the python tests python -m pytest @@ -20,8 +26,8 @@ if ($Env:GROUP -eq "integrity") { jlpm run integrity --force if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } - # Check yarn.lock file - jlpm check --integrity + # Validate the project + jlpm install --immutable --immutable-cache if ($LASTEXITCODE -ne 0) { throw "Command failed. See above errors for details" } # Run a browser check in dev mode diff --git a/scripts/ci_script.sh b/scripts/ci_script.sh index edd6e115a530..7272057148c4 100755 --- a/scripts/ci_script.sh +++ b/scripts/ci_script.sh @@ -6,13 +6,25 @@ set -ex set -o pipefail +# use a single global cache dir +export YARN_ENABLE_GLOBAL_CACHE=1 + +# display verbose output for pkg builds run during `jlpm install` +export YARN_ENABLE_INLINE_BUILDS=1 + + if [[ $GROUP != nonode ]]; then python -c "from jupyterlab.commands import build_check; build_check()" fi if [[ $GROUP == python ]]; then - jupyter lab build --debug + export JUPYTERLAB_DIR="${HOME}/share/jupyter/lab/" + mkdir -p $JUPYTERLAB_DIR + + # the env var ensures that `yarn.lock` in app dir does not change on a simple `jupyter lab build` call + YARN_ENABLE_IMMUTABLE_INSTALLS=1 jupyter lab build --debug --minimize=False + # Run the python tests python -m pytest fi @@ -20,13 +32,9 @@ fi if [[ $GROUP == js* ]]; then - if [[ $GROUP == "js-testutils" ]]; then - pushd testutils - else - # extract the group name - export PKG="${GROUP#*-}" - pushd packages/${PKG} - fi + # extract the group name + export PKG="${GROUP#*-}" + pushd packages/${PKG} jlpm run build:test; true @@ -39,12 +47,9 @@ fi if [[ $GROUP == docs ]]; then # Build the docs (includes API docs) + python -m pip install .[docs] pushd docs - conda env create -f environment.yml - conda init --all - source $CONDA/bin/activate jupyterlab_documentation make html - conda deactivate popd fi @@ -52,10 +57,16 @@ fi if [[ $GROUP == integrity ]]; then # Run the integrity script first jlpm run integrity --force - - # Check yarn.lock file - jlpm check --integrity - + # Validate the project + jlpm install --immutable --immutable-cache + jlpm dlx yarn-berry-deduplicate --strategy fewerHighest + # Here we should not be stringent as yarn may clean + # output of `yarn-berry-deduplicate` + jlpm install + if [[ "$(git status --porcelain | wc -l | sed -e "s/^[[:space:]]*//" -e "s/[[:space:]]*$//")" != "0" ]]; then + git diff + exit 1 + fi # Run a browser check in dev mode jlpm run build python -m jupyterlab.browser_check --dev-mode @@ -64,7 +75,15 @@ fi if [[ $GROUP == lint ]]; then # Lint our files. - jlpm run lint:check || (echo 'Please run `jlpm run lint` locally and push changes' && exit 1) + jlpm run prettier:check || (echo 'Please run `jlpm run prettier` locally and push changes' && exit 1) + jlpm run eslint:check || (echo 'Please run `jlpm run eslint` locally and push changes' && exit 1) + jlpm run eslint:check:typed || (echo echo 'Please run `jlpm run eslint:typed` locally and push changes' && exit 1) + jlpm run stylelint:check || (echo 'Please run `jlpm run stylelint` locally and push changes' && exit 1) + + # Python checks + black --check --diff --color . + ruff . + pipx run 'validate-pyproject[all]' pyproject.toml fi @@ -72,26 +91,14 @@ if [[ $GROUP == integrity2 ]]; then # Run the integrity script to link binary files jlpm integrity - # Check the manifest - check-manifest -v - # Build the packages individually. jlpm run build:src # Make sure we can build for release jlpm run build:dev:prod:release - # Make sure the storybooks build. - # Storybook is drop in JLab 4 as unused by active maintainers - # As NodeJS 18 is breaking storybook configuration, this test is removed from the CI. - # jlpm run build:storybook - - jlpm config set prefix ~/.yarn - # Make sure we have CSS that can be converted with postcss - jlpm global add postcss postcss-cli - - ~/.yarn/bin/postcss packages/**/style/*.css --dir /tmp + jlpm dlx -p postcss -p postcss-cli postcss packages/**/style/*.css --dir /tmp --config scripts/postcss.config.js # run twine check on the python build assets. # this must be done before altering any versions below. @@ -117,7 +124,7 @@ if [[ $GROUP == integrity3 ]]; then jlpm bumpversion release --force # switch to rc jlpm bumpversion build --force jlpm bumpversion next --force - VERSION=$(python setup.py --version) + VERSION=$(hatch version) if [[ $VERSION != *rc2 ]]; then exit 1; fi # make sure we can patch release @@ -152,6 +159,7 @@ if [[ $GROUP == release_test ]]; then node buildutils/lib/local-repository.js stop fi + if [[ $GROUP == examples ]]; then # Run the integrity script to link binary files jlpm integrity @@ -202,11 +210,11 @@ if [[ $GROUP == usage ]]; then jupyter labextension build extension # Test develop script with hyphens and underscores in the module name - pip install -e test-hyphens + python -m pip install -e test-hyphens jupyter labextension develop test-hyphens --overwrite --debug - pip install -e test_no_hyphens + python -m pip install -e test_no_hyphens jupyter labextension develop test_no_hyphens --overwrite --debug - pip install -e test-hyphens-underscore + python -m pip install -e test-hyphens-underscore jupyter labextension develop test-hyphens-underscore --overwrite --debug python -m jupyterlab.browser_check @@ -241,12 +249,6 @@ if [[ $GROUP == usage ]]; then jupyter labextension list -h jupyter labextension enable -h jupyter labextension disable -h - # Make sure we can add and remove a sibling package. - # jlpm run add:sibling jupyterlab/tests/mock_packages/extension - # jlpm run build - # jlpm run remove:package extension - # jlpm run build - # jlpm run integrity --force # Should have a clean tree now # Test cli tools jlpm run get:dependency mocha @@ -257,30 +259,8 @@ if [[ $GROUP == usage ]]; then jlpm run get:dependency react-native # Use the extension upgrade script - pip install cookiecutter + python -m pip install copier jinja2-time "pydantic<2" python -m jupyterlab.upgrade_extension --no-input jupyterlab/tests/mock_packages/extension - - # Test theme creation - make sure we can add it as a package, build, - # and run browser - pip install -q pexpect - python scripts/create_theme.py - mv foo packages - jlpm run integrity - jlpm run build:packages - jlpm run build:dev - python -m jupyterlab.browser_check --dev-mode - jlpm run remove:package foo - jlpm run integrity - - - # Make sure we can run JupyterLab under classic notebook - # It is not possible to run JupyterLab under classic notebook with Jupyter Server v2 installed. - pip install -U "jupyter_server<2.0.0" - python -m jupyterlab.browser_check - # For unknown reason, enabling manually the BrowserApp is needed lately - jupyter serverextension enable --sys-prefix --py jupyterlab.browser_check - jupyter serverextension list - python -m jupyterlab.browser_check --notebook fi @@ -313,26 +293,21 @@ if [[ $GROUP == usage2 ]]; then python -m jupyterlab.browser_check --watch # Make sure we can non-dev install. - virtualenv -p $(which python3) test_install - ./test_install/bin/pip install -q ".[test]" # this populates /share/jupyter/lab - - ./test_install/bin/jupyter server extension list 1>serverextensions 2>&1 - cat serverextensions - cat serverextensions | grep -i "jupyterlab.*enabled" - cat serverextensions | grep -i "jupyterlab.*OK" + TEST_INSTALL_PATH="${HOME}/test_install" + virtualenv -p $(which python3) $TEST_INSTALL_PATH + $TEST_INSTALL_PATH/bin/pip install -q ".[dev,test]" # this populates /share/jupyter/lab - # TODO: remove when we no longer support classic notebook - ./test_install/bin/jupyter serverextension list 1>serverextensions 2>&1 + $TEST_INSTALL_PATH/bin/jupyter server extension list 1>serverextensions 2>&1 cat serverextensions cat serverextensions | grep -i "jupyterlab.*enabled" cat serverextensions | grep -i "jupyterlab.*OK" - ./test_install/bin/python -m jupyterlab.browser_check + $TEST_INSTALL_PATH/bin/python -m jupyterlab.browser_check # Make sure we can run the build - ./test_install/bin/jupyter lab build + $TEST_INSTALL_PATH/bin/jupyter lab build # Make sure we can start and kill the lab server - ./test_install/bin/jupyter lab --no-browser & + $TEST_INSTALL_PATH/bin/jupyter lab --no-browser & TASK_PID=$! # Make sure the task is running ps -p $TASK_PID || exit 1 @@ -341,9 +316,9 @@ if [[ $GROUP == usage2 ]]; then wait $TASK_PID # Check the labhubapp - ./test_install/bin/pip install jupyterhub + $TEST_INSTALL_PATH/bin/pip install jupyterhub export JUPYTERHUB_API_TOKEN="mock_token" - ./test_install/bin/jupyter-labhub --HubOAuth.oauth_client_id="mock_id" & + $TEST_INSTALL_PATH/bin/jupyter-labhub --HubOAuth.oauth_client_id="mock_id" & TASK_PID=$! unset JUPYTERHUB_API_TOKEN # Make sure the task is running @@ -399,7 +374,7 @@ if [[ $GROUP == interop ]]; then popd pushd provider jupyter labextension build . - pip install . + python -m pip install . popd pushd consumer jupyter labextension install . @@ -423,7 +398,7 @@ if [[ $GROUP == interop ]]; then popd pushd consumer jupyter labextension build . - pip install . + python -m pip install . popd jupyter labextension list 1>labextensions 2>&1 cat labextensions | grep -q "@jupyterlab/mock-consumer.*OK" @@ -447,7 +422,7 @@ if [[ $GROUP == interop ]]; then # if installed after jupyter labextension install . jupyter labextension build . - pip install . + python -m pip install . popd jupyter labextension list 1>labextensions 2>&1 cat labextensions | grep -q "@jupyterlab/mock-consumer.*OK" diff --git a/scripts/create_theme.py b/scripts/create_theme.py deleted file mode 100644 index 5d323e99138a..000000000000 --- a/scripts/create_theme.py +++ /dev/null @@ -1,16 +0,0 @@ -# coding: utf-8 -"""JupyterLab command handler""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import pexpect - -child = pexpect.spawn("node buildutils/lib/create-theme.js") -child.expect("name:") -child.sendline("foo") -child.expect("title:") -child.sendline("Foo") -child.expect("description:") -child.sendline("foo theme") -child.expect("Created new theme") diff --git a/scripts/docs_push.sh b/scripts/docs_push.sh deleted file mode 100644 index e3aa343741df..000000000000 --- a/scripts/docs_push.sh +++ /dev/null @@ -1,14 +0,0 @@ - -#!/bin/bash - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -jlpm -jlpm build:packages -jlpm docs -cd docs/api -git init -touch .nojekyll # disable jekyll -git add . -git commit -m "Deploy to GitHub Pages" -git push --force "https://github.com/jupyterlab/jupyterlab" master:gh-pages diff --git a/scripts/generate_changelog.py b/scripts/generate_changelog.py deleted file mode 100644 index 83f6672fba2c..000000000000 --- a/scripts/generate_changelog.py +++ /dev/null @@ -1,32 +0,0 @@ -""" Generate a changelog for JupyterLab from the GitHub releases """ - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import re - -import dateutil.parser -import requests - -# Get the list of releases. -r = requests.get("https://api.github.com/repos/jupyterlab/jupyterlab/releases") - -if r.status_code == 200: - releases = r.json() - with open("CHANGELOG.md", "w") as f: - f.write("# JupyterLab Changelog\n\n") - for release in releases: - name = release["name"] - tag_name = release["tag_name"] - tag_url = release["html_url"] - tag_date = dateutil.parser.parse(release["published_at"]) - notes = release["body"].replace("\r\n", "\n") - notes = re.sub( - r"#([0-9]+)", r"[#\1](https://github.com/jupyterlab/jupyterlab/issues/\1)", notes - ) - - title = f"{name} ({tag_name})" if name != tag_name else name - f.write(f"## [{title}]({tag_url})\n") - f.write(f'#### {tag_date.strftime("%b %d, %Y")}\n') - f.write(notes) - f.write("\n\n") diff --git a/scripts/i18n_check.py b/scripts/i18n_check.py index 6db3671dbdb5..4e6502e50771 100644 --- a/scripts/i18n_check.py +++ b/scripts/i18n_check.py @@ -19,12 +19,12 @@ wrapwidth=100000, ) - hash = sha256() + hash_ = sha256() # Use only the context and the id as the position may changed without impact # Sort the entry because the order in the POT file may changed (likely because code position changed) - for entry in sorted(map(lambda e: f"{e.msgctxt!s} {e.msgid!s}", pot)): - hash.update(entry.encode("utf-8")) + for entry in sorted(map(lambda e: f"{e.msgctxt!s} {e.msgid!s}", pot)): # noqa + hash_.update(entry.encode("utf-8")) - proof = hash.hexdigest() + proof = hash_.hexdigest() print(proof) diff --git a/scripts/milestone_check.py b/scripts/milestone_check.py index 905a4c30bf3d..0999e40067c2 100644 --- a/scripts/milestone_check.py +++ b/scripts/milestone_check.py @@ -26,7 +26,7 @@ "2.1": "origin/2.1.x --not origin/2.0.x", "2.2": "origin/2.2.x --not origin/2.1.x", # 6507205805 is a commit in the debugger ancestor tree before merging - "3.0": "origin/master ^origin/2.2.x ^6507205805", + "3.0": "origin/main ^origin/2.2.x ^6507205805", } try: @@ -35,27 +35,27 @@ print( "Error: set the environment variable GITHUB_TOKEN to a GitHub authentication token (see https://github.com/settings/tokens)" ) - exit(1) + sys.exit(1) -if len(sys.argv) != 2: +if len(sys.argv) != 2: # noqa print("Error: exactly one argument expected, the milestone.") - exit(1) + sys.exit(1) MILESTONE = sys.argv[1] if MILESTONE not in ranges: print( - "Error: I do not know about milestone %r. Possible milestones are %r" - % (MILESTONE, list(ranges.keys())) + f"Error: I do not know about milestone {MILESTONE!r}. Possible milestones are {list(ranges.keys())!r}" ) - exit(1) + sys.exit(1) out = subprocess.run( - "git log {} --format='%H,%cE,%s'".format(ranges[MILESTONE]), - shell=True, + f"git log {ranges[MILESTONE]} --format='%H,%cE,%s'", + shell=True, # noqa S602 encoding="utf8", stdout=subprocess.PIPE, + check=True, ) commits = {i[0]: (i[1], i[2]) for i in (x.split(",", 2) for x in out.stdout.splitlines())} @@ -102,19 +102,19 @@ cursor = None while True: json["variables"]["cursor"] = cursor - r = requests.post(url=url, json=json, headers=headers) + r = requests.post(url=url, json=json, headers=headers, timeout=120) results = r.json()["data"]["search"] total_prs = results["issueCount"] pr_list = results["nodes"] for pr in pr_list: - if pr["commits"]["totalCount"] > 100: + if pr["commits"]["totalCount"] > 100: # noqa large_prs.append(pr["number"]) continue # TODO fetch commits prs[pr["number"]] = { "mergeCommit": pr["mergeCommit"]["oid"], - "commits": set(i["commit"]["oid"] for i in pr["commits"]["nodes"]), + "commits": {i["commit"]["oid"] for i in pr["commits"]["nodes"]}, } has_next_page = results["pageInfo"]["hasNextPage"] @@ -156,9 +156,9 @@ prjson["variables"]["pr"] = prnumber pr_commits = set() while True: - r = requests.post(url=url, json=prjson, headers=headers) + r = requests.post(url=url, json=prjson, headers=headers, timeout=120) pr = r.json()["data"]["repository"]["pullRequest"] - assert pr["number"] == prnumber + assert pr["number"] == prnumber # noqa total_commits = pr["commits"]["totalCount"] pr_commits.update(i["commit"]["oid"] for i in pr["commits"]["nodes"]) has_next_page = results["pageInfo"]["hasNextPage"] @@ -177,7 +177,7 @@ # Check we got all PRs -assert len(prs) == total_prs +assert len(prs) == total_prs # noqa # Reverse dictionary commits_to_prs = {} @@ -206,7 +206,7 @@ if len(prs_not_represented) > 0: print( """ -PRs that are in the milestone, but have no commits in the version range. +PRs that are in the milestone, but have no commits in the version range. These PRs probably belong in a different milestone. """ ) @@ -228,10 +228,10 @@ print( """The following commits are not included in any PR on this milestone. This probably means the commit's PR needs to be assigned to this milestone, -or the commit was pushed to master directly. +or the commit was pushed to main directly. """ ) - print("\n".join("%s %s %s" % (c, commits[c][0], commits[c][1]) for c in notfound)) + print("\n".join(f"{c} {commits[c][0]} {commits[c][1]}" for c in notfound)) prs_to_check = [ c for c in notfound @@ -243,7 +243,7 @@ "Try checking these PRs. They probably should be in the milestone, but probably aren't:" ) print() - print("\n".join("%s %s" % (c, commits[c][1]) for c in prs_to_check)) + print("\n".join(f"{c} {commits[c][1]}" for c in prs_to_check)) else: print( "Congratulations! All commits in the commit history are included in some PR in this milestone." diff --git a/scripts/postcss.config.js b/scripts/postcss.config.js new file mode 100644 index 000000000000..9efaf920aa7d --- /dev/null +++ b/scripts/postcss.config.js @@ -0,0 +1,10 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +// for the integrity2 CI in scripts/ci_script.sh +module.exports = { + // use a postcss plugin that already exists in the top-level project + plugins: [require('postcss-selector-parser')] +}; diff --git a/scripts/release_prep.sh b/scripts/release_prep.sh index bb28cf614246..5253b82fa55a 100755 --- a/scripts/release_prep.sh +++ b/scripts/release_prep.sh @@ -1,3 +1,8 @@ +#!/bin/bash +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + + # Prep a fresh conda environment in a temporary folder for a release if [[ $# -ne 1 ]]; then echo "Specify branch" diff --git a/scripts/release_test.sh b/scripts/release_test.sh index 2042edc224ba..a39a958b5651 100755 --- a/scripts/release_test.sh +++ b/scripts/release_test.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + # Test a release wheel in a fresh conda environment with and without installed # extensions @@ -19,7 +22,6 @@ python -m pip install $(ls dist/*.whl) cp examples/notebooks/*.ipynb $TEST_DIR/ cp -r jupyterlab/tests/mock_packages $TEST_DIR - pushd $TEST_DIR ls -ltr @@ -29,6 +31,8 @@ JLAB_BROWSER_CHECK_OUTPUT=${OUTPUT_DIR} python -m jupyterlab.browser_check # Remove node_modules to get a clean directory and build the extensions rm -rf ./mock_packages/mimeextension/node_modules rm -rf ./mock_packages/extension/node_modules + +export YARN_NPM_REGISTRY_SERVER="http://0.0.0.0:4873" jupyter labextension install ./mock_packages/mimeextension --no-build --debug jupyter labextension develop ./mock_packages/extension --debug jupyter labextension build ./mock_packages/extension --debug diff --git a/scripts/watch_dev.py b/scripts/watch_dev.py index cbde28ecfb36..41edc7888b77 100644 --- a/scripts/watch_dev.py +++ b/scripts/watch_dev.py @@ -1,5 +1,3 @@ -# coding: utf-8 - # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. diff --git a/scripts/watch_packages.py b/scripts/watch_packages.py index 246d6c5aab93..ce4759a6d9f7 100644 --- a/scripts/watch_packages.py +++ b/scripts/watch_packages.py @@ -1,5 +1,3 @@ -# coding: utf-8 - # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index e9413f5c3dfc..000000000000 --- a/setup.cfg +++ /dev/null @@ -1,71 +0,0 @@ -[metadata] -name = jupyterlab -version = attr: jupyterlab._version.__version__ -description = JupyterLab computational environment -long_description = file: README.md -long_description_content_type = text/markdown -license_file = LICENSE -author = Jupyter Development Team -author_email = jupyter@googlegroups.com -url = https://jupyter.org -platforms = Linux, Mac OS X, Windows -keywords = ipython, jupyter -classifiers = - Development Status :: 5 - Production/Stable - Framework :: Jupyter - Framework :: Jupyter :: JupyterLab - Framework :: Jupyter :: JupyterLab :: 3 - Intended Audience :: Developers - Intended Audience :: System Administrators - Intended Audience :: Science/Research - License :: OSI Approved :: BSD License - Programming Language :: Python - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - -[options] -zip_safe = False -include_package_data = True -packages = find: -python_requires = >=3.7 -install_requires = - ipython - packaging - tornado>=6.1.0 - jupyter_core - jupyterlab_server~=2.19 - jupyter_server @ git+https://github.com/spotinst/jupyter_server.git@v2.6.0-ocean - jupyter_ydoc~=0.2.4 - jupyter_server_ydoc~=0.8.0 - nbclassic - notebook<7 - jinja2>=2.1 - tomli;python_version<"3.11" - -[options.extras_require] -test = - check-manifest - coverage - jupyterlab_server[test] - pre-commit - pytest>=6.0 - pytest-cov - pytest-console-scripts - pytest-check-links>=0.5 - pytest-jupyter>=0.5.3 - requests - requests_cache - virtualenv - -[options.entry_points] -console_scripts = - jupyter-lab = jupyterlab.labapp:main - jupyter-labextension = jupyterlab.labextensions:main - jupyter-labhub = jupyterlab.labhubapp:main - jlpm = jupyterlab.jlpmapp:main - -[options.packages.find] -exclude = ['docs*', 'examples*'] diff --git a/setup.py b/setup.py index 3f67e8b7689e..4abca77c3086 100644 --- a/setup.py +++ b/setup.py @@ -1,100 +1,5 @@ -#!/usr/bin/env python -# coding: utf-8 - -import json -import os -import os.path as osp -import subprocess -import sys - # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from os.path import join as pjoin - -from setuptools import setup - -NAME = "jupyterlab" -HERE = osp.dirname(osp.abspath(__file__)) - -ensured_targets = [ - "static/package.json", - "schemas/@jupyterlab/shortcuts-extension/shortcuts.json", - "themes/@jupyterlab/theme-light-extension/index.css", -] -ensured_targets = [osp.join(HERE, NAME, t) for t in ensured_targets] - -data_files_spec = [ - ("share/jupyter/lab/static", f"{NAME}/static", "**"), - ("share/jupyter/lab/schemas", f"{NAME}/schemas", "**"), - ("share/jupyter/lab/themes", f"{NAME}/themes", "**"), - ( - "etc/jupyter/jupyter_server_config.d", - "jupyter-config/jupyter_server_config.d", - f"{NAME}.json", - ), - ( - "etc/jupyter/jupyter_notebook_config.d", - "jupyter-config/jupyter_notebook_config.d", - f"{NAME}.json", - ), -] - - -def post_dist(): - from jupyter_packaging import get_version - from packaging.version import Version - - target = pjoin(HERE, NAME, "static", "package.json") - with open(target) as fid: - version = json.load(fid)["jupyterlab"]["version"] - - if Version(version) != Version(get_version(f"{NAME}/_version.py")): - raise ValueError("Version mismatch, please run `build:update`") - - -try: - from jupyter_packaging import get_data_files, npm_builder, wrap_installers - - npm = ["node", pjoin(HERE, NAME, "staging", "yarn.js")] - # In develop mode, just run yarn, unless this is an sdist. - if os.path.exists(os.path.join(HERE, "buildutils")): - builder = npm_builder(build_cmd=None, npm=npm, force=True) - - def post_develop(*args, **kwargs): - builder(*args, **kwargs) - try: - import pre_commit - except ImportError: - print( - "Please install pre-commit and the associated hooks; using the following commands:" - ) - print("pip install pre-commit") - print("python -m pre_commit install") - print("python -m pre_commit install --hook-type pre-push") - - else: - try: - subprocess.run([sys.executable, "-m", "pre_commit", "install"]) - subprocess.run( - [sys.executable, "-m", "pre_commit", "install", "--hook-type", "pre-push"] - ) - except Exception: - # no-op - pass - - cmdclass = wrap_installers( - post_develop=post_develop, post_dist=post_dist, ensured_targets=ensured_targets - ) - else: - cmdclass = wrap_installers(post_dist=post_dist, ensured_targets=ensured_targets) - - setup_args = dict( - cmdclass=cmdclass, - data_files=get_data_files(data_files_spec) - ) -except ImportError: - setup_args = dict() - -if __name__ == "__main__": - setup(**setup_args) +# setup.py shim for use with applications that require it. +__import__("setuptools").setup() diff --git a/testutils/babel.config.js b/testutils/babel.config.js deleted file mode 100644 index 1b995256375e..000000000000 --- a/testutils/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/babel.config'); diff --git a/testutils/jest.config.js b/testutils/jest.config.js deleted file mode 100644 index 7a7c7265b191..000000000000 --- a/testutils/jest.config.js +++ /dev/null @@ -1,2 +0,0 @@ -const func = require('./lib/jest-config'); -module.exports = func(__dirname); diff --git a/testutils/package.json b/testutils/package.json index 49c5c5ea748c..0692288955f1 100644 --- a/testutils/package.json +++ b/testutils/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/testutils", - "version": "3.6.6", + "version": "4.0.8", "description": "JupyterLab - Test Utilities", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -22,54 +22,24 @@ "lib/*.js.map", "lib/*.js", "default*.json", - "tsconfigtestbase.json" + "tsconfigtestbase.json", + "src/**/*.{ts,tsx}" ], "scripts": { "build": "tsc -b", - "build:all": "npm run build", - "build:test": "tsc --build tsconfig.test.json", "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", - "test": "jest", - "test:cov": "jest --collect-coverage", - "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/apputils": "^3.6.6", - "@jupyterlab/cells": "^3.6.6", - "@jupyterlab/codeeditor": "^3.6.6", - "@jupyterlab/codemirror": "^3.6.6", - "@jupyterlab/coreutils": "^5.6.6", - "@jupyterlab/docregistry": "^3.6.6", - "@jupyterlab/nbformat": "^3.6.6", - "@jupyterlab/notebook": "^3.6.6", - "@jupyterlab/rendermime": "^3.6.6", - "@jupyterlab/services": "^6.6.6", - "@lumino/algorithm": "^1.9.0", - "@lumino/coreutils": "^1.11.0", - "@lumino/properties": "^1.8.0", - "@lumino/signaling": "^1.10.0", - "child_process": "~1.0.2", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.1", - "identity-obj-proxy": "^3.0.0", - "jest": "^26.4.2", - "jest-junit": "^11.1.0", - "jest-raw-loader": "^1.0.1", - "jest-summary-reporter": "^0.0.2", - "json-to-html": "~0.1.2", - "markdown-loader-jest": "^0.1.1", - "node-fetch": "^2.6.0", - "simulate-event": "~1.4.0", - "ts-jest": "^26.3.0" + "@jupyterlab/application": "^4.0.8", + "@jupyterlab/apputils": "^4.1.8", + "@jupyterlab/notebook": "^4.0.8", + "@jupyterlab/rendermime": "^4.0.8", + "@jupyterlab/testing": "^4.0.8" }, "devDependencies": { - "@types/jest": "^26.0.10", - "@types/node-fetch": "^2.5.4", - "jest-retries": "^1.0.1", - "lighthouse": "6.3.0", - "typescript": "~4.1.3" + "rimraf": "~3.0.0", + "typescript": "~5.0.4" }, "publishConfig": { "access": "public" diff --git a/testutils/src/babel.config.ts b/testutils/src/babel.config.ts index 6c3be4c41b2d..f102cb899b57 100644 --- a/testutils/src/babel.config.ts +++ b/testutils/src/babel.config.ts @@ -1,12 +1,8 @@ -module.exports = { - presets: [ - [ - '@babel/preset-env', - { - targets: { - node: 'current' - } - } - ] - ] -}; +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import * as config from '@jupyterlab/testing/lib/babel-config'; + +module.exports = config; diff --git a/testutils/src/compare-lighthouse.ts b/testutils/src/compare-lighthouse.ts deleted file mode 100644 index c4fb4e80e5b9..000000000000 --- a/testutils/src/compare-lighthouse.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Compares two files lighthouse outputs, listing changes between the numeric audits. - * - * Outputs in Markdown for easy posting in Github. - */ -import { readFileSync } from 'fs-extra'; - -const firstFilePath = process.argv[2]; -const secondFilePath = process.argv[3]; - -console.debug(`\`${firstFilePath}\` -> \`${secondFilePath}\`\n\n`); -interface IOutput { - audits: { - [name: string]: { - id: string; - title: string; - description: string; - scoreDisplayMode: string; - displayValue: string; - numericValue: number; - }; - }; -} - -const first: IOutput = JSON.parse(readFileSync(firstFilePath).toString()); -const second: IOutput = JSON.parse(readFileSync(secondFilePath).toString()); - -for (const auditName in first.audits) { - const firstAudit = first.audits[auditName]; - - // only compare numeric audits - if (firstAudit.scoreDisplayMode !== 'numeric') { - continue; - } - const secondAudit = second.audits[auditName]; - const percentChange = - ((secondAudit.numericValue - firstAudit.numericValue) / - firstAudit.numericValue) * - 100; - - if (isNaN(percentChange)) { - continue; - } - console.debug( - `**${firstAudit.title}**\n* ${percentChange.toFixed(0)}% Δ\n* ${ - firstAudit.displayValue - } -> ${secondAudit.displayValue}\n* ${firstAudit.description}\n` - ); -} diff --git a/testutils/src/flakyIt.ts b/testutils/src/flakyIt.ts deleted file mode 100644 index 9d85e274bd23..000000000000 --- a/testutils/src/flakyIt.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Adapted from https://github.com/bluzi/jest-retries/blob/01a9713a7379edcfd2d1bccec7c0fbc66d4602da/src/retry.js - -// We explicitly reference the jest typings since the jest.d.ts file shipped -// with jest 26 masks the @types/jest typings - -/// - -import { sleep } from './common'; - -/** - * Run a test function. - * - * @param fn The function of the test - */ -async function runTest(fn: any): Promise { - return new Promise((resolve, reject) => { - const result = fn((err: Error) => (err ? reject(err) : resolve())); - - if (result && result.then) { - result.catch(reject).then(resolve); - } else { - resolve(); - } - }); -} - -/** - * Run a flaky test with retries. - * - * @param name The name of the test - * @param fn The function of the test - * @param retries The number of retries - * @param wait The time to wait in milliseconds between retries - */ -/* eslint-disable jest/no-export */ -export function flakyIt(name: string, fn: any, retries = 3, wait = 1000): void { - test(name, async () => { - let latestError; - for (let tries = 0; tries < retries; tries++) { - try { - await runTest(fn); - return; - } catch (error) { - latestError = error; - await sleep(wait); - } - } - throw latestError; - }); -} -/* eslint-enable jest/no-export */ - -flakyIt.only = it.only; -flakyIt.skip = it.skip; -flakyIt.todo = it.todo; diff --git a/testutils/src/index.ts b/testutils/src/index.ts index 6e10c0f22bc0..6faab0686861 100644 --- a/testutils/src/index.ts +++ b/testutils/src/index.ts @@ -1,36 +1,31 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -export { NBTestUtils } from './notebook-utils'; - -export { defaultRenderMime } from './rendermime'; - -export { FakeUserManager } from './user'; - -export { JupyterServer } from './start_jupyter_server'; - +export { createSessionContext } from '@jupyterlab/apputils/lib/testutils'; export { - testEmission, - expectFailure, - signalToPromises, - signalToPromise, - isFulfilled, - framePromise, - sleep, - createSessionContext, - createSession, createFileContext, createFileContextWithKernel, + createSession, + DocumentWidgetOpenerMock +} from '@jupyterlab/docregistry/lib/testutils'; +export { initNotebookContext, - waitForDialog, + NBTestUtils +} from '@jupyterlab/notebook/lib/testutils'; +export { defaultRenderMime } from '@jupyterlab/rendermime/lib/testutils'; +export * as Mock from './mock'; +export { FakeUserManager } from '@jupyterlab/services/lib/testutils'; +export { acceptDialog, dangerDialog, dismissDialog, - simulate -} from './common'; - -export { flakyIt } from './flakyIt'; - -import * as Mock from './mock'; - -export { Mock }; + expectFailure, + framePromise, + isFulfilled, + JupyterServer, + signalToPromise, + signalToPromises, + sleep, + testEmission, + waitForDialog +} from '@jupyterlab/testing'; diff --git a/testutils/src/jest-config.ts b/testutils/src/jest-config.ts index 970bcb8149ca..ae420f1586d3 100644 --- a/testutils/src/jest-config.ts +++ b/testutils/src/jest-config.ts @@ -1,46 +1,8 @@ -import path from 'path'; +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ -const esModules = [ - '@jupyter/ydoc', - 'lib0', - 'y-protocols', - 'y-websocket', - 'yjs' -].join('|'); +import func from '@jupyterlab/testing/lib/jest-config'; -module.exports = function (baseDir: string) { - return { - preset: 'ts-jest/presets/js-with-babel', - moduleNameMapper: { - '\\.(css|less|sass|scss)$': 'identity-obj-proxy', - '\\.(gif|ttf|eot)$': '@jupyterlab/testutils/lib/jest-file-mock.js' - }, - transform: { - '\\.svg$': 'jest-raw-loader', - '^.+\\.md?$': 'markdown-loader-jest' - }, - testTimeout: 10000, - setupFiles: ['@jupyterlab/testutils/lib/jest-shim.js'], - testPathIgnorePatterns: ['/lib/', '/node_modules/'], - moduleFileExtensions: [ - 'ts', - 'tsx', - 'js', - 'jsx', - 'json', - 'node', - 'mjs', - 'cjs' - ], - transformIgnorePatterns: [`/node_modules/(?!${esModules}).+`], - reporters: ['default', 'jest-junit', 'jest-summary-reporter'], - coverageReporters: ['json', 'lcov', 'text', 'html'], - coverageDirectory: path.join(baseDir, 'coverage'), - testRegex: '/test/.*.spec.ts[x]?$', - globals: { - 'ts-jest': { - tsconfig: `./tsconfig.test.json` - } - } - }; -}; +module.exports = func; diff --git a/testutils/src/jest-file-mock.ts b/testutils/src/jest-file-mock.ts deleted file mode 100644 index 86059f362924..000000000000 --- a/testutils/src/jest-file-mock.ts +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'test-file-stub'; diff --git a/testutils/src/json-to-html.d.ts b/testutils/src/json-to-html.d.ts deleted file mode 100644 index ef066f50e5d0..000000000000 --- a/testutils/src/json-to-html.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Type definitions for json2html v0.1.2 -// https://github.com/frozzare/json-to-html -// Definitions by: Steven Silvester - -declare module 'json-to-html' { - function render(value: any): string; - export = render; -} diff --git a/testutils/src/mock.ts b/testutils/src/mock.ts index 2f7566ca1611..d461beb052a9 100644 --- a/testutils/src/mock.ts +++ b/testutils/src/mock.ts @@ -1,875 +1,20 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -// We explicitly reference the jest typings since the jest.d.ts file shipped -// with jest 26 masks the @types/jest typings - -/// - -import { ISessionContext, SessionContext } from '@jupyterlab/apputils'; - -import { Context, TextModelFactory } from '@jupyterlab/docregistry'; - -import { - Contents, - ContentsManager, - Kernel, - KernelMessage, - KernelSpec, - ServerConnection, - ServiceManager, - Session -} from '@jupyterlab/services'; - -import { ArrayIterator } from '@lumino/algorithm'; - -import { AttachedProperty } from '@lumino/properties'; - -import { UUID } from '@lumino/coreutils'; - -import { Signal } from '@lumino/signaling'; - -import { PathExt } from '@jupyterlab/coreutils'; - -// The default kernel name -export const DEFAULT_NAME = 'python3'; - -export const KERNELSPECS: { [key: string]: KernelSpec.ISpecModel } = { - [DEFAULT_NAME]: { - argv: [ - '/Users/someuser/miniconda3/envs/jupyterlab/bin/python', - '-m', - 'ipykernel_launcher', - '-f', - '{connection_file}' - ], - display_name: 'Python 3', - language: 'python', - metadata: {}, - name: DEFAULT_NAME, - resources: {} - }, - irkernel: { - argv: [ - '/Users/someuser/miniconda3/envs/jupyterlab/bin/python', - '-m', - 'ipykernel_launcher', - '-f', - '{connection_file}' - ], - display_name: 'R', - language: 'python', - metadata: {}, - name: 'irkernel', - resources: {} - } -}; - -export const KERNEL_MODELS: Kernel.IModel[] = [ - { - name: DEFAULT_NAME, - id: UUID.uuid4() - }, - { - name: 'r', - id: UUID.uuid4() - }, - { - name: DEFAULT_NAME, - id: UUID.uuid4() - } -]; - -// Notebook Paths for certain kernel name -export const NOTEBOOK_PATHS: { [kernelName: string]: string[] } = { - python3: ['Untitled.ipynb', 'Untitled1.ipynb', 'Untitled2.ipynb'], - r: ['Visualization.ipynb', 'Analysis.ipynb', 'Conclusion.ipynb'] -}; - -/** - * Forceably change the status of a session context. - * An iopub message is emitted for the change. - * - * @param sessionContext The session context of interest. - * @param newStatus The new kernel status. - */ -export function updateKernelStatus( - sessionContext: ISessionContext, - newStatus: KernelMessage.Status -) { - const kernel = sessionContext.session!.kernel!; - (kernel as any).status = newStatus; - (sessionContext.statusChanged as any).emit(newStatus); - const msg = KernelMessage.createMessage({ - session: kernel.clientId, - channel: 'iopub', - msgType: 'status', - content: { execution_state: newStatus } - }); - emitIopubMessage(sessionContext, msg); -} - -/** - * Emit an iopub message on a session context. - * - * @param sessionContext The session context - * @param msg Message created with `KernelMessage.createMessage` - */ -export function emitIopubMessage( - context: ISessionContext, - msg: KernelMessage.IIOPubMessage -): void { - const kernel = context!.session!.kernel!; - const msgId = Private.lastMessageProperty.get(kernel); - (msg.parent_header as any).session = kernel.clientId; - (msg.parent_header as any).msg_id = msgId; - (kernel.iopubMessage as any).emit(msg); -} - -/** - * Create a session context given a partial session model. - * - * @param model The session model to use. - */ -export function createSimpleSessionContext( - model: Private.RecursivePartial = {} -): ISessionContext { - const kernel = new KernelMock({ model: model?.kernel || {} }); - const session = new SessionConnectionMock({ model }, kernel); - return new SessionContextMock({}, session); -} - -/** - * Clone a kernel connection. - */ -export function cloneKernel( - kernel: Kernel.IKernelConnection -): Kernel.IKernelConnection { - return (kernel as any).clone(); -} - -/** - * A mock kernel object. - * - * @param model The model of the kernel - */ -export const KernelMock = jest.fn< - Kernel.IKernelConnection, - [Private.RecursivePartial] ->(options => { - const model = { id: 'foo', name: DEFAULT_NAME, ...options.model }; - options = { - clientId: UUID.uuid4(), - username: UUID.uuid4(), - ...options, - model - }; - let executionCount = 0; - const spec = Private.kernelSpecForKernelName(model.name)!; - const thisObject: Kernel.IKernelConnection = { - ...jest.requireActual('@jupyterlab/services'), - ...options, - ...model, - status: 'idle', - spec: Promise.resolve(spec), - dispose: jest.fn(), - clone: jest.fn(() => { - const newKernel = Private.cloneKernel(options); - newKernel.iopubMessage.connect((_, args) => { - iopubMessageSignal.emit(args); - }); - newKernel.statusChanged.connect((_, args) => { - (thisObject as any).status = args; - statusChangedSignal.emit(args); - }); - return newKernel; - }), - info: Promise.resolve(Private.getInfo(model!.name!)), - shutdown: jest.fn(() => Promise.resolve(void 0)), - requestHistory: jest.fn(() => { - const historyReply = KernelMessage.createMessage({ - channel: 'shell', - msgType: 'history_reply', - session: options.clientId!, - username: options.username!, - content: { - history: [], - status: 'ok' - } - }); - return Promise.resolve(historyReply); - }), - restart: jest.fn(() => Promise.resolve(void 0)), - requestExecute: jest.fn(options => { - const msgId = UUID.uuid4(); - executionCount++; - Private.lastMessageProperty.set(thisObject, msgId); - const msg = KernelMessage.createMessage({ - channel: 'iopub', - msgType: 'execute_input', - session: thisObject.clientId, - username: thisObject.username, - msgId, - content: { - code: options.code, - execution_count: executionCount - } - }); - iopubMessageSignal.emit(msg); - const reply = KernelMessage.createMessage( - { - channel: 'shell', - msgType: 'execute_reply', - session: thisObject.clientId, - username: thisObject.username, - msgId, - content: { - user_expressions: {}, - execution_count: executionCount, - status: 'ok' - } - } - ); - return new MockShellFuture(reply) as Kernel.IShellFuture< - KernelMessage.IExecuteRequestMsg, - KernelMessage.IExecuteReplyMsg - >; - }) - } as any; // FIXME: fix the typing error this any cast is ignoring - // Add signals. - const iopubMessageSignal = new Signal< - Kernel.IKernelConnection, - KernelMessage.IIOPubMessage - >(thisObject); - const statusChangedSignal = new Signal< - Kernel.IKernelConnection, - Kernel.Status - >(thisObject); - const pendingInputSignal = new Signal( - thisObject - ); - (thisObject as any).statusChanged = statusChangedSignal; - (thisObject as any).iopubMessage = iopubMessageSignal; - (thisObject as any).pendingInput = pendingInputSignal; - (thisObject as any).hasPendingInput = false; - return thisObject; -}); - -/** - * A mock session connection. - * - * @param options Addition session options to use - * @param model A session model to use - */ -export const SessionConnectionMock = jest.fn< - Session.ISessionConnection, - [ - Private.RecursivePartial, - Kernel.IKernelConnection | null - ] ->((options, kernel) => { - const name = kernel?.name || options.model?.kernel?.name || DEFAULT_NAME; - kernel = kernel || new KernelMock({ model: { name } }); - const model = { - path: 'foo', - type: 'notebook', - name: 'foo', - ...options.model, - kernel: kernel!.model - }; - const thisObject: Session.ISessionConnection = { - ...jest.requireActual('@jupyterlab/services'), - id: UUID.uuid4(), - ...options, - model, - ...model, - kernel, - dispose: jest.fn(), - changeKernel: jest.fn(partialModel => { - return Private.changeKernel(kernel!, partialModel!); - }), - shutdown: jest.fn(() => Promise.resolve(void 0)), - setPath: jest.fn(path => { - (thisObject as any).path = path; - propertyChangedSignal.emit('path'); - return Promise.resolve(); - }), - setName: jest.fn(name => { - (thisObject as any).name = name; - propertyChangedSignal.emit('name'); - return Promise.resolve(); - }), - setType: jest.fn(type => { - (thisObject as any).type = type; - propertyChangedSignal.emit('type'); - return Promise.resolve(); - }) - } as any; // FIXME: fix the typing error this any cast is ignoring - const disposedSignal = new Signal( - thisObject - ); - const propertyChangedSignal = new Signal< - Session.ISessionConnection, - 'path' | 'name' | 'type' - >(thisObject); - const statusChangedSignal = new Signal< - Session.ISessionConnection, - Kernel.Status - >(thisObject); - const connectionStatusChangedSignal = new Signal< - Session.ISessionConnection, - Kernel.ConnectionStatus - >(thisObject); - const kernelChangedSignal = new Signal< - Session.ISessionConnection, - Session.ISessionConnection.IKernelChangedArgs - >(thisObject); - const iopubMessageSignal = new Signal< - Session.ISessionConnection, - KernelMessage.IIOPubMessage - >(thisObject); - - const unhandledMessageSignal = new Signal< - Session.ISessionConnection, - KernelMessage.IMessage - >(thisObject); - - const pendingInputSignal = new Signal( - thisObject - ); - - kernel!.iopubMessage.connect((_, args) => { - iopubMessageSignal.emit(args); - }, thisObject); - - kernel!.statusChanged.connect((_, args) => { - statusChangedSignal.emit(args); - }, thisObject); - - kernel!.pendingInput.connect((_, args) => { - pendingInputSignal.emit(args); - }, thisObject); - - (thisObject as any).disposed = disposedSignal; - (thisObject as any).connectionStatusChanged = connectionStatusChangedSignal; - (thisObject as any).propertyChanged = propertyChangedSignal; - (thisObject as any).statusChanged = statusChangedSignal; - (thisObject as any).kernelChanged = kernelChangedSignal; - (thisObject as any).iopubMessage = iopubMessageSignal; - (thisObject as any).unhandledMessage = unhandledMessageSignal; - (thisObject as any).pendingInput = pendingInputSignal; - return thisObject; -}); - -/** - * A mock session context. - * - * @param session The session connection object to use - */ -export const SessionContextMock = jest.fn< - ISessionContext, - [Partial, Session.ISessionConnection | null] ->((options, connection) => { - const session = - connection || - new SessionConnectionMock( - { - model: { - path: options.path || '', - type: options.type || '', - name: options.name || '' - } - }, - null - ); - const thisObject: ISessionContext = { - ...jest.requireActual('@jupyterlab/apputils'), - ...options, - path: session.path, - type: session.type, - name: session.name, - kernel: session.kernel, - session, - dispose: jest.fn(), - initialize: jest.fn(() => Promise.resolve()), - ready: Promise.resolve(), - changeKernel: jest.fn(partialModel => { - return Private.changeKernel( - session.kernel || Private.RUNNING_KERNELS[0], - partialModel! - ); - }), - shutdown: jest.fn(() => Promise.resolve()) - } as any; // FIXME: fix the typing error this any cast is ignoring - - const disposedSignal = new Signal(thisObject); - - const propertyChangedSignal = new Signal< - ISessionContext, - 'path' | 'name' | 'type' - >(thisObject); - - const statusChangedSignal = new Signal( - thisObject - ); - const kernelChangedSignal = new Signal< - ISessionContext, - Session.ISessionConnection.IKernelChangedArgs - >(thisObject); - - const iopubMessageSignal = new Signal< - ISessionContext, - KernelMessage.IIOPubMessage - >(thisObject); - - session!.statusChanged.connect((_, args) => { - statusChangedSignal.emit(args); - }, thisObject); - - session!.iopubMessage.connect((_, args) => { - iopubMessageSignal.emit(args); - }); - - session!.kernelChanged.connect((_, args) => { - kernelChangedSignal.emit(args); - }); - - session!.pendingInput.connect((_, args) => { - (thisObject as any).pendingInput = args; - }); - - (thisObject as any).statusChanged = statusChangedSignal; - (thisObject as any).kernelChanged = kernelChangedSignal; - (thisObject as any).iopubMessage = iopubMessageSignal; - (thisObject as any).propertyChanged = propertyChangedSignal; - (thisObject as any).disposed = disposedSignal; - (thisObject as any).session = session; - (thisObject as any).pendingInput = false; - - return thisObject; -}); - -/** - * A mock contents manager. - */ -export const ContentsManagerMock = jest.fn(() => { - const files = new Map(); - const dummy = new ContentsManager(); - const checkpoints = new Map(); - const checkPointContent = new Map(); - - const baseModel = Private.createFile({ type: 'directory' }); - files.set('', { ...baseModel, path: '', name: '' }); - - const thisObject: Contents.IManager = { - ...jest.requireActual('@jupyterlab/services'), - newUntitled: jest.fn(options => { - const model = Private.createFile(options || {}); - files.set(model.path, model); - fileChangedSignal.emit({ - type: 'new', - oldValue: null, - newValue: model - }); - return Promise.resolve(model); - }), - createCheckpoint: jest.fn(path => { - const lastModified = new Date().toISOString(); - const data = { id: UUID.uuid4(), last_modified: lastModified }; - checkpoints.set(path, data); - checkPointContent.set(path, files.get(path)?.content); - return Promise.resolve(data); - }), - listCheckpoints: jest.fn(path => { - const p = checkpoints.get(path); - if (p !== undefined) { - return Promise.resolve([p]); - } - return Promise.resolve([]); - }), - deleteCheckpoint: jest.fn(path => { - if (!checkpoints.has(path)) { - return Private.makeResponseError(404); - } - checkpoints.delete(path); - return Promise.resolve(); - }), - restoreCheckpoint: jest.fn(path => { - if (!checkpoints.has(path)) { - return Private.makeResponseError(404); - } - (files.get(path) as any).content = checkPointContent.get(path); - return Promise.resolve(); - }), - getModelDBFactory: jest.fn(() => { - return null; - }), - normalize: jest.fn(path => { - return dummy.normalize(path); - }), - localPath: jest.fn(path => { - return dummy.localPath(path); - }), - resolvePath: jest.fn((root, path) => { - return dummy.resolvePath(root, path); - }), - get: jest.fn((path, options) => { - path = Private.fixSlash(path); - if (!files.has(path)) { - return Private.makeResponseError(404); - } - const model = files.get(path)!; - if (model.type === 'directory') { - if (options?.content !== false) { - const content: Contents.IModel[] = []; - files.forEach(fileModel => { - if (PathExt.dirname(fileModel.path) == model.path) { - content.push(fileModel); - } - }); - return Promise.resolve({ ...model, content }); - } - return Promise.resolve(model); - } - if (options?.content != false) { - return Promise.resolve(model); - } - return Promise.resolve({ ...model, content: '' }); - }), - driveName: jest.fn(path => { - return dummy.driveName(path); - }), - rename: jest.fn((oldPath, newPath) => { - oldPath = Private.fixSlash(oldPath); - newPath = Private.fixSlash(newPath); - if (!files.has(oldPath)) { - return Private.makeResponseError(404); - } - const oldValue = files.get(oldPath)!; - files.delete(oldPath); - const name = PathExt.basename(newPath); - const newValue = { ...oldValue, name, path: newPath }; - files.set(newPath, newValue); - fileChangedSignal.emit({ - type: 'rename', - oldValue, - newValue - }); - return Promise.resolve(newValue); - }), - delete: jest.fn(path => { - path = Private.fixSlash(path); - if (!files.has(path)) { - return Private.makeResponseError(404); - } - const oldValue = files.get(path)!; - files.delete(path); - fileChangedSignal.emit({ - type: 'delete', - oldValue, - newValue: null - }); - return Promise.resolve(void 0); - }), - save: jest.fn((path, options) => { - if (path == 'readonly.txt') { - return Private.makeResponseError(403); - } - path = Private.fixSlash(path); - const timeStamp = new Date().toISOString(); - if (files.has(path)) { - files.set(path, { - ...files.get(path)!, - ...options, - last_modified: timeStamp - }); - } else { - files.set(path, { - path, - name: PathExt.basename(path), - content: '', - writable: true, - created: timeStamp, - type: 'file', - format: 'text', - mimetype: 'plain/text', - ...options, - last_modified: timeStamp - }); - } - fileChangedSignal.emit({ - type: 'save', - oldValue: null, - newValue: files.get(path)! - }); - return Promise.resolve(files.get(path)!); - }), - getDownloadUrl: jest.fn(path => { - return dummy.getDownloadUrl(path); - }), - addDrive: jest.fn(drive => { - dummy.addDrive(drive); - }), - dispose: jest.fn() - }; - - const fileChangedSignal = new Signal< - Contents.IManager, - Contents.IChangedArgs - >(thisObject); - (thisObject as any).fileChanged = fileChangedSignal; - return thisObject; -}); - -/** - * A mock sessions manager. - */ -export const SessionManagerMock = jest.fn(() => { - let sessions: Session.IModel[] = []; - const thisObject: Session.IManager = { - ...jest.requireActual('@jupyterlab/services'), - ready: Promise.resolve(void 0), - isReady: true, - startNew: jest.fn(options => { - const session = new SessionConnectionMock({ model: options }, null); - sessions.push(session.model); - runningChangedSignal.emit(sessions); - return Promise.resolve(session); - }), - connectTo: jest.fn(options => { - return new SessionConnectionMock(options, null); - }), - stopIfNeeded: jest.fn(path => { - const length = sessions.length; - sessions = sessions.filter(model => model.path !== path); - if (sessions.length !== length) { - runningChangedSignal.emit(sessions); - } - return Promise.resolve(void 0); - }), - refreshRunning: jest.fn(() => Promise.resolve(void 0)), - running: jest.fn(() => new ArrayIterator(sessions)) - }; - - const runningChangedSignal = new Signal( - thisObject - ); - (thisObject as any).runningChanged = runningChangedSignal; - return thisObject; -}); - -/** - * A mock kernel specs manager - */ -export const KernelSpecManagerMock = jest.fn(() => { - const thisObject: KernelSpec.IManager = { - ...jest.requireActual('@jupyterlab/services'), - specs: { default: DEFAULT_NAME, kernelspecs: KERNELSPECS }, - isReady: true, - ready: Promise.resolve(void 0), - refreshSpecs: jest.fn(() => Promise.resolve(void 0)) - }; - return thisObject; -}); - -/** - * A mock service manager. - */ -export const ServiceManagerMock = jest.fn(() => { - const thisObject: ServiceManager.IManager = { - ...jest.requireActual('@jupyterlab/services'), - ready: Promise.resolve(void 0), - isReady: true, - contents: new ContentsManagerMock(), - sessions: new SessionManagerMock(), - kernelspecs: new KernelSpecManagerMock(), - dispose: jest.fn() - }; - return thisObject; -}); - -/** - * A mock kernel shell future. - */ -export const MockShellFuture = jest.fn< - Kernel.IShellFuture, - [KernelMessage.IShellMessage] ->((result: KernelMessage.IShellMessage) => { - const thisObject: Kernel.IShellFuture = { - ...jest.requireActual('@jupyterlab/services'), - dispose: jest.fn(), - done: Promise.resolve(result) - }; - return thisObject; -}); - -/** - * Create a context for a file. - */ -export async function createFileContext( - startKernel = false, - manager?: ServiceManager.IManager -): Promise { - const path = UUID.uuid4() + '.txt'; - manager = manager || new ServiceManagerMock(); - const factory = new TextModelFactory(); - - const context = new Context({ - manager: manager || new ServiceManagerMock(), - factory, - path, - kernelPreference: { - shouldStart: startKernel, - canStart: startKernel, - autoStartDefault: startKernel - } - }); - await context.initialize(true); - await context.sessionContext.initialize(); - return context; -} - -/** - * A namespace for module private data. - */ -namespace Private { - export function flattenArray(arr: T[][]): T[] { - const result: T[] = []; - - arr.forEach(innerArr => { - innerArr.forEach(elem => { - result.push(elem); - }); - }); - - return result; - } - - export type RecursivePartial = { - [P in keyof T]?: RecursivePartial; - }; - - export function createFile( - options?: Contents.ICreateOptions - ): Contents.IModel { - options = options || {}; - let name = UUID.uuid4(); - switch (options.type) { - case 'directory': - name = `Untitled Folder_${name}`; - break; - case 'notebook': - name = `Untitled_${name}.ipynb`; - break; - default: - name = `untitled_${name}${options.ext || '.txt'}`; - } - - const path = PathExt.join(options.path || '', name); - let content = ''; - if (options.type === 'notebook') { - content = JSON.stringify({}); - } - const timeStamp = new Date().toISOString(); - return { - path, - content, - name, - last_modified: timeStamp, - writable: true, - created: timeStamp, - type: options.type || 'file', - format: 'text', - mimetype: 'plain/text' - }; - } - - export function fixSlash(path: string): string { - if (path.endsWith('/')) { - path = path.slice(0, path.length - 1); - } - return path; - } - - export function makeResponseError(status: number): Promise { - const resp = new Response(void 0, { status }); - return Promise.reject(new ServerConnection.ResponseError(resp)); - } - - export function cloneKernel( - options: RecursivePartial - ): Kernel.IKernelConnection { - return new KernelMock({ ...options, clientId: UUID.uuid4() }); - } - - // Get the kernel spec for kernel name - export function kernelSpecForKernelName(name: string) { - return KERNELSPECS[name]; - } - - // Get the kernel info for kernel name - export function getInfo(name: string): KernelMessage.IInfoReply { - return { - protocol_version: '1', - implementation: 'foo', - implementation_version: '1', - language_info: { - version: '1', - name - }, - banner: 'hello, world!', - help_links: [], - status: 'ok' - }; - } - - export function changeKernel( - kernel: Kernel.IKernelConnection, - partialModel: Partial - ): Promise { - if (partialModel.id) { - const kernelIdx = KERNEL_MODELS.findIndex(model => { - return model.id === partialModel.id; - }); - if (kernelIdx !== -1) { - (kernel.model as any) = RUNNING_KERNELS[kernelIdx].model; - (kernel.id as any) = partialModel.id; - return Promise.resolve(RUNNING_KERNELS[kernelIdx]); - } else { - throw new Error( - `Unable to change kernel to one with id: ${partialModel.id}` - ); - } - } else if (partialModel.name) { - const kernelIdx = KERNEL_MODELS.findIndex(model => { - return model.name === partialModel.name; - }); - if (kernelIdx !== -1) { - (kernel.model as any) = RUNNING_KERNELS[kernelIdx].model; - (kernel.id as any) = partialModel.id; - return Promise.resolve(RUNNING_KERNELS[kernelIdx]); - } else { - throw new Error( - `Unable to change kernel to one with name: ${partialModel.name}` - ); - } - } else { - throw new Error(`Unable to change kernel`); - } - } - - // This list of running kernels simply mirrors the KERNEL_MODELS and KERNELSPECS lists - export const RUNNING_KERNELS: Kernel.IKernelConnection[] = KERNEL_MODELS.map( - (model, _) => { - return new KernelMock({ model }); - } - ); - - export const lastMessageProperty = new AttachedProperty< - Kernel.IKernelConnection, - string - >({ - name: 'lastMessageId', - create: () => '' - }); -} +export { + createFileContext, + createSimpleSessionContext, + DocumentWidgetOpenerMock, + emitIopubMessage, + SessionContextMock, + updateKernelStatus +} from '@jupyterlab/docregistry/lib/testutils'; +export { + cloneKernel, + ContentsManagerMock, + DEFAULT_NAME, + KERNELSPECS, + KERNEL_MODELS, + NOTEBOOK_PATHS, + SessionConnectionMock +} from '@jupyterlab/services/lib/testutils'; diff --git a/testutils/src/notebook-utils.ts b/testutils/src/notebook-utils.ts deleted file mode 100644 index 000ccf26ee5f..000000000000 --- a/testutils/src/notebook-utils.ts +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import { UUID } from '@lumino/coreutils'; - -import { editorServices } from '@jupyterlab/codemirror'; - -import { CodeEditorWrapper } from '@jupyterlab/codeeditor'; - -import { Clipboard } from '@jupyterlab/apputils'; - -import * as nbformat from '@jupyterlab/nbformat'; - -import { Context, DocumentRegistry } from '@jupyterlab/docregistry'; - -import { - INotebookModel, - Notebook, - NotebookModel, - NotebookModelFactory, - NotebookPanel, - NotebookWidgetFactory, - StaticNotebook -} from '@jupyterlab/notebook'; - -import { RenderMimeRegistry } from '@jupyterlab/rendermime'; - -import { Cell, CodeCellModel } from '@jupyterlab/cells'; - -import { defaultRenderMime as localRendermime } from './rendermime'; - -import * as Mock from './mock'; - -/** - * Stub for the require() function. - */ -declare let require: any; - -/** - * The default notebook content. - */ -// tslint:disable-next-line - -export namespace NBTestUtils { - /** - * The default outputs used for testing. - */ - export const DEFAULT_OUTPUTS: nbformat.IOutput[] = [ - { - name: 'stdout', - output_type: 'stream', - text: ['hello world\n', '0\n', '1\n', '2\n'] - }, - { - name: 'stderr', - output_type: 'stream', - text: ['output to stderr\n'] - }, - { - name: 'stderr', - output_type: 'stream', - text: ['output to stderr2\n'] - }, - { - output_type: 'execute_result', - execution_count: 1, - data: { 'text/plain': 'foo' }, - metadata: {} - }, - { - output_type: 'display_data', - data: { 'text/plain': 'hello, world' }, - metadata: {} - }, - { - output_type: 'error', - ename: 'foo', - evalue: 'bar', - traceback: ['fizz', 'buzz'] - } - ]; - - export const DEFAULT_CONTENT: nbformat.INotebookContent = require('../default.json') as nbformat.INotebookContent; - export const DEFAULT_CONTENT_45: nbformat.INotebookContent = require('../default-45.json') as nbformat.INotebookContent; - - export const defaultEditorConfig = { ...StaticNotebook.defaultEditorConfig }; - - export const editorFactory = editorServices.factoryService.newInlineEditor.bind( - editorServices.factoryService - ); - - export const mimeTypeService = editorServices.mimeTypeService; - - /** - * Get a copy of the default rendermime instance. - */ - export function defaultRenderMime(): RenderMimeRegistry { - return localRendermime(); - } - - export const clipboard = Clipboard.getInstance(); - - /** - * Create a base cell content factory. - */ - export function createBaseCellFactory(): Cell.IContentFactory { - return new Cell.ContentFactory({ editorFactory }); - } - - /** - * Create a new code cell content factory. - */ - export function createCodeCellFactory(): Cell.IContentFactory { - return new Cell.ContentFactory({ editorFactory }); - } - - /** - * Create a cell editor widget. - */ - export function createCellEditor(model?: CodeCellModel): CodeEditorWrapper { - return new CodeEditorWrapper({ - model: model || new CodeCellModel({}), - factory: editorFactory - }); - } - - /** - * Create a default notebook content factory. - */ - export function createNotebookFactory(): Notebook.IContentFactory { - return new Notebook.ContentFactory({ editorFactory }); - } - - /** - * Create a default notebook panel content factory. - */ - export function createNotebookPanelFactory(): NotebookPanel.IContentFactory { - return new NotebookPanel.ContentFactory({ editorFactory }); - } - - /** - * Create a notebook widget. - */ - export function createNotebook(): Notebook { - return new Notebook({ - rendermime: defaultRenderMime(), - contentFactory: createNotebookFactory(), - mimeTypeService - }); - } - - /** - * Create a notebook panel widget. - */ - export function createNotebookPanel( - context: Context - ): NotebookPanel { - return new NotebookPanel({ - content: createNotebook(), - context - }); - } - - /** - * Populate a notebook with default content. - */ - export function populateNotebook(notebook: Notebook): void { - const model = new NotebookModel(); - model.fromJSON(DEFAULT_CONTENT); - notebook.model = model; - } - - export function createNotebookWidgetFactory( - toolbarFactory?: (widget: NotebookPanel) => DocumentRegistry.IToolbarItem[] - ): NotebookWidgetFactory { - return new NotebookWidgetFactory({ - name: 'notebook', - fileTypes: ['notebook'], - rendermime: defaultRenderMime(), - toolbarFactory, - contentFactory: createNotebookPanelFactory(), - mimeTypeService: mimeTypeService, - editorConfig: defaultEditorConfig - }); - } - - /** - * Create a context for a file. - */ - export async function createMockContext( - startKernel = false - ): Promise> { - const path = UUID.uuid4() + '.txt'; - const manager = new Mock.ServiceManagerMock(); - const factory = new NotebookModelFactory({}); - - const context = new Context({ - manager, - factory, - path, - kernelPreference: { - shouldStart: startKernel, - canStart: startKernel, - autoStartDefault: startKernel - } - }); - await context.initialize(true); - await context.sessionContext.initialize(); - return context; - } -} diff --git a/testutils/src/rendermime.ts b/testutils/src/rendermime.ts deleted file mode 100644 index 289142eba84a..000000000000 --- a/testutils/src/rendermime.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -import json2html from 'json-to-html'; - -import { - IRenderMime, - RenderedHTML, - RenderMimeRegistry, - standardRendererFactories -} from '@jupyterlab/rendermime'; - -/** - * Get a copy of the default rendermime instance. - */ -export function defaultRenderMime(): RenderMimeRegistry { - return Private.rendermime.clone(); -} - -/** - * A namespace for private data. - */ -namespace Private { - class JSONRenderer extends RenderedHTML { - mimeType = 'text/html'; - - renderModel(model: IRenderMime.IMimeModel): Promise { - const source = model.data['application/json']; - model.setData({ data: { 'text/html': json2html(source) } }); - return super.renderModel(model); - } - } - - const jsonRendererFactory = { - mimeTypes: ['application/json'], - safe: true, - createRenderer( - options: IRenderMime.IRendererOptions - ): IRenderMime.IRenderer { - return new JSONRenderer(options); - } - }; - - export const rendermime = new RenderMimeRegistry({ - initialFactories: standardRendererFactories - }); - rendermime.addFactory(jsonRendererFactory, 10); -} diff --git a/testutils/tsconfig.json b/testutils/tsconfig.json index a59143ff5009..9971a7d8d497 100644 --- a/testutils/tsconfig.json +++ b/testutils/tsconfig.json @@ -3,30 +3,16 @@ "compilerOptions": { "outDir": "lib", "rootDir": "src", - "module": "commonjs" + "module": "commonjs", + "types": ["node"] }, "include": ["src/*"], "references": [ { - "path": "../packages/apputils" - }, - { - "path": "../packages/cells" - }, - { - "path": "../packages/codeeditor" - }, - { - "path": "../packages/codemirror" - }, - { - "path": "../packages/coreutils" + "path": "../packages/application" }, { - "path": "../packages/docregistry" - }, - { - "path": "../packages/nbformat" + "path": "../packages/apputils" }, { "path": "../packages/notebook" @@ -35,7 +21,7 @@ "path": "../packages/rendermime" }, { - "path": "../packages/services" + "path": "../packages/testing" } ] } diff --git a/testutils/tsconfig.test.json b/testutils/tsconfig.test.json deleted file mode 100644 index d9e4f2d1ec58..000000000000 --- a/testutils/tsconfig.test.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "extends": "../tsconfigbase.test", - "include": ["src/*", "test/*"], - "references": [ - { - "path": "../packages/apputils" - }, - { - "path": "../packages/cells" - }, - { - "path": "../packages/codeeditor" - }, - { - "path": "../packages/codemirror" - }, - { - "path": "../packages/coreutils" - }, - { - "path": "../packages/docregistry" - }, - { - "path": "../packages/nbformat" - }, - { - "path": "../packages/notebook" - }, - { - "path": "../packages/rendermime" - }, - { - "path": "../packages/services" - }, - { - "path": "." - }, - { - "path": "../packages/apputils" - }, - { - "path": "../packages/cells" - }, - { - "path": "../packages/codeeditor" - }, - { - "path": "../packages/codemirror" - }, - { - "path": "../packages/coreutils" - }, - { - "path": "../packages/docregistry" - }, - { - "path": "../packages/nbformat" - }, - { - "path": "../packages/notebook" - }, - { - "path": "../packages/rendermime" - }, - { - "path": "../packages/services" - } - ] -} diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 927744729693..e3f5cca15623 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -4,27 +4,28 @@ "packages/**/src/**/*", "packages/**/test/**/*", "packages/**/style/**/*", - "testutils/src/*", + "testutils/**/*", "builder/**/*", "buildutils/**/*", "tests/**/*", "dev_mode/*", "docs/**/*", ".eslintrc.js", + ".eslintrc.typecheck.js", "examples/**/*", "galata/.eslintrc.js", "galata/*.config.js", + "galata/extension/**/*", "galata/src/**/*", "galata/test/**/*", "galata/style/**/*", "*", "packages/services/examples/**/*", + "packages/testing/**/*", "packages/**/*.config.js", "packages/metapackage/build-doc-index.js", - "packages/**/stories/*", "scripts/*", "jupyterlab/*", - "jupyterlab/staging/*", - "testutils/**/*" + "jupyterlab/staging/*" ] } diff --git a/tsconfigbase.json b/tsconfigbase.json index 4b68a32401fc..347c6e3082bb 100644 --- a/tsconfigbase.json +++ b/tsconfigbase.json @@ -17,7 +17,7 @@ "resolveJsonModule": true, "sourceMap": true, "strictNullChecks": true, - "target": "es2017", + "target": "ES2018", "types": [] } } diff --git a/tsconfigbase.test.json b/tsconfigbase.test.json index d1e9c841ec39..b95721c156e3 100644 --- a/tsconfigbase.test.json +++ b/tsconfigbase.test.json @@ -6,9 +6,9 @@ "noUnusedLocals": true, "module": "commonjs", "moduleResolution": "node", - "target": "es2018", + "target": "ES2018", "outDir": "lib", - "lib": ["DOM", "ES2018"], + "lib": ["DOM", "DOM.iterable"], "types": ["jest", "node"], "jsx": "react", "resolveJsonModule": true, diff --git a/tsconfigdoc.json b/tsconfigdoc.json index b31636c680ac..30b2d309d274 100644 --- a/tsconfigdoc.json +++ b/tsconfigdoc.json @@ -3,7 +3,8 @@ "extends": "./tsconfigbase", "exclude": [ "**/test/**", - "**/testutils/**" + "**/testutils/**", + "packages/testing/**" ], "compilerOptions": { "strictNullChecks": false, @@ -12,6 +13,11 @@ "./packages/*/src" ] }, + "lib": [ + "DOM", + "DOM.iterable", + "es2019.array" + ], "moduleResolution": "node", "types": [ "jest", @@ -40,9 +46,6 @@ { "path": "./packages/cells" }, - { - "path": "./packages/celltags" - }, { "path": "./packages/celltags-extension" }, @@ -55,12 +58,6 @@ { "path": "./packages/codemirror-extension" }, - { - "path": "./packages/collaboration" - }, - { - "path": "./packages/collaboration-extension" - }, { "path": "./packages/completer" }, @@ -94,12 +91,6 @@ { "path": "./packages/docmanager-extension" }, - { - "path": "./packages/docprovider" - }, - { - "path": "./packages/docprovider-extension" - }, { "path": "./packages/docregistry" }, @@ -169,6 +160,12 @@ { "path": "./packages/logconsole-extension" }, + { + "path": "./packages/lsp" + }, + { + "path": "./packages/lsp-extension" + }, { "path": "./packages/mainmenu" }, @@ -182,10 +179,16 @@ "path": "./packages/markdownviewer-extension" }, { - "path": "./packages/mathjax2" + "path": "./packages/markedparser-extension" + }, + { + "path": "./packages/mathjax-extension" + }, + { + "path": "./packages/metadataform" }, { - "path": "./packages/mathjax2-extension" + "path": "./packages/metadataform-extension" }, { "path": "./packages/nbformat" @@ -235,9 +238,6 @@ { "path": "./packages/settingregistry" }, - { - "path": "./packages/shared-models" - }, { "path": "./packages/shortcuts-extension" }, @@ -286,12 +286,6 @@ { "path": "./packages/ui-components-extension" }, - { - "path": "./packages/vdom" - }, - { - "path": "./packages/vdom-extension" - }, { "path": "./packages/vega5-extension" } diff --git a/typedoc.js b/typedoc.js index a6ce92425eb2..d2b89bda4c1a 100644 --- a/typedoc.js +++ b/typedoc.js @@ -1,97 +1,69 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const fs = require('fs'); +// Most of the -extension packages are useless as their +// public API is the plugins array. Add them only if they +// export other items. const packages = [ - // 'application-extension', 'application', - 'apputils-extension', 'apputils', 'attachments', 'cells', - 'celltags-extension', - 'celltags', 'codeeditor', - 'codemirror-extension', 'codemirror', - 'collaboration', - 'collaboration-extension', - 'completer-extension', 'completer', - 'console-extension', 'console', 'coreutils', - 'csvviewer-extension', 'csvviewer', - 'debugger-extension', 'debugger', - 'docprovider-extension', - 'docprovider', 'docmanager-extension', 'docmanager', 'docregistry', 'documentsearch-extension', 'documentsearch', - 'extensionmanager-extension', 'extensionmanager', - 'filebrowser-extension', 'filebrowser', 'fileeditor-extension', 'fileeditor', - 'help-extension', - 'htmlviewer-extension', 'htmlviewer', 'hub-extension', 'imageviewer-extension', 'imageviewer', - 'inspector-extension', 'inspector', 'javascript-extension', 'json-extension', - 'launcher-extension', 'launcher', 'logconsole-extension', 'logconsole', + 'lsp-extension', 'mainmenu-extension', 'mainmenu', - 'markdownviewer-extension', 'markdownviewer', - 'mathjax2-extension', - 'mathjax2', - // 'metapackage', - // 'nbconvert-css', + 'mathjax-extension', 'nbformat', - 'notebook-extension', 'notebook', 'observables', 'outputarea', 'pdf-extension', 'property-inspector', - 'rendermime-extension', 'rendermime-interfaces', 'rendermime', 'running-extension', 'running', 'services', - 'settingeditor-extension', 'settingeditor', 'settingregistry', - 'shortcuts-extension', 'statedb', - 'statusbar-extension', 'statusbar', - 'terminal-extension', 'terminal', - 'theme-dark-extension', - 'theme-light-extension', 'toc', - 'toc-extension', - 'tooltip-extension', 'tooltip', - 'translation-extension', 'translation', - 'ui-components-extension', 'ui-components', - 'vdom-extension', - 'vdom', 'vega5-extension' ]; @@ -103,27 +75,157 @@ const entryPoints = packages const exclude = packages.flatMap(p => [`packages/${p}/test`]) + - [ - 'packages/application-extension/src/index.tsx' - //'packages/*/test/*.spec.ts', - ]; + ['packages/application-extension']; module.exports = { entryPoints, exclude, + externalSymbolLinkMappings: { + '@codemirror/language': { + LanguageSupport: + 'https://codemirror.net/docs/ref/#language.LanguageSupport' + }, + '@codemirror/state': { + Extension: 'https://codemirror.net/docs/ref/#state.Extension', + SelectionRange: 'https://codemirror.net/docs/ref/#state.SelectionRange', + StateEffect: 'https://codemirror.net/docs/ref/#state.StateEffect' + }, + '@jupyter/ydoc': { + createStandaloneCell: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/functions/createStandaloneCell.html', + DocumentChange: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/types/DocumentChange.html', + FileChange: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/types/FileChange.html', + IMapChange: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/IMapChange.html', + ISharedAttachmentsCell: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedAttachmentsCell.html', + ISharedCell: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/types/ISharedCell.html', + ISharedCodeCell: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedCodeCell.html', + ISharedDocument: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedDocument.html', + ISharedFile: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedFile.html', + ISharedMarkdownCell: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedMarkdownCell.html', + ISharedNotebook: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedNotebook-1.html', + ISharedRawCell: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedRawCell.html', + ISharedText: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedText.html', + IYText: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/IYText.html', + NotebookChange: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/types/NotebookChange.html', + SourceChange: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/types/SourceChange.html', + YCodeCell: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/classes/YCodeCell.html', + YDocument: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/classes/YDocument-1.html', + YFile: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/classes/YFile.html', + YNotebook: + 'https://jupyter-ydoc.readthedocs.io/en/latest/api/classes/YNotebook.html' + }, + '@lumino/application': { + Application: + 'https://lumino.readthedocs.io/en/latest/api/classes/application.Application-1.html', + IPlugin: + 'https://lumino.readthedocs.io/en/latest/api/interfaces/application.IPlugin.html' + }, + '@lumino/coreutils': { + JSONObject: + 'https://lumino.readthedocs.io/en/latest/api/interfaces/coreutils.JSONObject.html', + JSONValue: + 'https://lumino.readthedocs.io/en/latest/api/types/coreutils.JSONValue.html', + PartialJSONValue: + 'https://lumino.readthedocs.io/en/latest/api/types/coreutils.PartialJSONValue.html', + ReadonlyJSONObject: + 'https://lumino.readthedocs.io/en/latest/api/interfaces/coreutils.ReadonlyJSONObject.html', + ReadonlyPartialJSONObject: + 'https://lumino.readthedocs.io/en/latest/api/interfaces/coreutils.ReadonlyPartialJSONObject.html', + Token: + 'https://lumino.readthedocs.io/en/latest/api/classes/coreutils.Token.html' + }, + '@lumino/disposable': { + IDisposable: + 'https://lumino.readthedocs.io/en/latest/api/interfaces/disposable.IDisposable.html', + IObservableDisposable: + 'https://lumino.readthedocs.io/en/latest/api/interfaces/disposable.IObservableDisposable.html' + }, + '@lumino/signaling': { + ISignal: + 'https://lumino.readthedocs.io/en/latest/api/interfaces/signaling.ISignal.html', + Signal: + 'https://lumino.readthedocs.io/en/latest/api/classes/signaling.Signal-1.html' + }, + '@lumino/virtualdom': { + VirtualElement: + 'https://lumino.readthedocs.io/en/stable/api/modules/virtualdom.VirtualElement.html', + 'VirtualElement.IRenderer': + 'https://lumino.readthedocs.io/en/latest/api/types/virtualdom.VirtualElement.IRenderer.html' + }, + '@lumino/widgets': { + ContextMenu: + 'https://lumino.readthedocs.io/en/stable/api/classes/widgets.ContextMenu-1.html', + 'ContextMenu.IOptions': + 'https://lumino.readthedocs.io/en/stable/api/interfaces/widgets.ContextMenu.IOptions.html', + DockPanel: + 'https://lumino.readthedocs.io/en/stable/api/classes/widgets.DockPanel-1.html', + 'DockPanel.IOptions': + 'https://lumino.readthedocs.io/en/stable/api/interfaces/widgets.DockPanel.IOptions.html', + Menu: 'https://lumino.readthedocs.io/en/stable/api/classes/widgets.Menu-1.html', + 'Menu.IItem': + 'https://lumino.readthedocs.io/en/stable/api/interfaces/widgets.Menu.IItem.html', + 'Menu.IItemOptions': + 'https://lumino.readthedocs.io/en/stable/api/interfaces/widgets.Menu.IItemOptions.html', + 'MenuBar.Renderer': + 'https://lumino.readthedocs.io/en/stable/api/classes/widgets.MenuBar.Renderer.html', + 'MenuBar.IRenderData': + 'https://lumino.readthedocs.io/en/stable/api/interfaces/widgets.MenuBar.IRenderData.html', + Panel: + 'https://lumino.readthedocs.io/en/stable/api/classes/widgets.Panel-1.html', + PanelLayout: + 'https://lumino.readthedocs.io/en/stable/api/classes/widgets.PanelLayout.html', + SplitPanel: + 'https://lumino.readthedocs.io/en/latest/api/classes/widgets.SplitPanel-1.html', + TabBar: + 'https://lumino.readthedocs.io/en/stable/api/classes/widgets.TabBar-1.html', + 'TabBar.IOptions': + 'https://lumino.readthedocs.io/en/stable/api/interfaces/widgets.TabBar.IOptions.html', + TabPanel: + 'https://lumino.readthedocs.io/en/stable/api/classes/widgets.TabPanel-1.html', + 'TabPanel.IOptions': + 'https://lumino.readthedocs.io/en/stable/api/interfaces/widgets.TabPanel.IOptions.html', + Widget: + 'https://lumino.readthedocs.io/en/latest/api/classes/widgets.Widget-1.html' + }, + '@rjsf/utils': { + FieldProps: + 'https://rjsf-team.github.io/react-jsonschema-form/docs/advanced-customization/custom-widgets-fields/#field-props' + }, + yjs: { + RelativePosition: 'https://docs.yjs.dev/api/relative-positions', + UndoManager: 'https://docs.yjs.dev/api/undo-manager', + Text: 'https://docs.yjs.dev/api/shared-types/y.text', + YText: 'https://docs.yjs.dev/api/shared-types/y.text' + } + }, + githubPages: false, + navigationLinks: { + GitHub: 'https://github.com/jupyterlab/jupyterlab', + Jupyter: 'https://jupyter.org' + }, name: '@jupyterlab', - out: 'docs/api', - // json: 'docs/api.json', + plugin: ['typedoc-plugin-mdn-links'], + out: 'docs/source/api', readme: 'README.md', - theme: 'typedoc-theme', + theme: 'default', + titleLink: 'https://jupyterlab.readthedocs.io/en/latest', tsconfig: 'tsconfigdoc.json' - - // theme: minimal, - // excludePrivate: true, - // excludeProtected: true, - // excludeExternals: true, - // hideGenerator: true - - // gitRevision: 'master', - // 'sourcefile-url-prefix': `https://github.com/sinnerschrader/feature-hub/tree/${git.short()}/packages/`, }; diff --git a/yarn.lock b/yarn.lock index 41e79810e63a..dbcf43acde67 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,18035 +1,20498 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.5.5": - version "7.15.8" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.15.8.tgz#45990c47adadb00c03677baa89221f7cc23d2503" - integrity sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg== - dependencies: - "@babel/highlight" "^7.14.5" - -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" - integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== - -"@babel/core@^7.1.0", "@babel/core@^7.10.2", "@babel/core@^7.12.3", "@babel/core@^7.7.5": - version "7.15.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" - integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helpers" "^7.15.4" - "@babel/parser" "^7.15.5" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - -"@babel/generator@^7.12.11", "@babel/generator@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.4.tgz#85acb159a267ca6324f9793986991ee2022a05b0" - integrity sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw== - dependencies: - "@babel/types" "^7.15.4" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.14.5", "@babel/helper-annotate-as-pure@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz#3d0e43b00c5e49fdb6c57e421601a7a658d5f835" - integrity sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz#b939b43f8c37765443a19ae74ad8b15978e0a191" - integrity sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.14.5" - "@babel/types" "^7.14.5" - -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" - integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-validator-option" "^7.14.5" - browserslist "^4.16.6" - semver "^6.3.0" - -"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz#7f977c17bd12a5fba363cb19bea090394bf37d2e" - integrity sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-member-expression-to-functions" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - -"@babel/helper-create-regexp-features-plugin@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4" - integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A== - dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - regexpu-core "^4.7.1" - -"@babel/helper-define-polyfill-provider@^0.2.2": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6" - integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew== - 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-explode-assignable-expression@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz#8aa72e708205c7bb643e45c73b4386cdf2a1f645" - integrity sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ== - dependencies: - "@babel/types" "^7.14.5" - -"@babel/helper-function-name@^7.14.5", "@babel/helper-function-name@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" - 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" - -"@babel/helper-get-function-arity@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" - integrity sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-hoist-variables@^7.14.5", "@babel/helper-hoist-variables@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" - integrity sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-member-expression-to-functions@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" - integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" - integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.4": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz#7da80c8cbc1f02655d83f8b79d25866afe50d226" - integrity sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw== - dependencies: - "@babel/helper-module-imports" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-simple-access" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/helper-validator-identifier" "^7.15.7" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.6" - -"@babel/helper-optimise-call-expression@^7.14.5", "@babel/helper-optimise-call-expression@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" - integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" - integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== - -"@babel/helper-remap-async-to-generator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz#51439c913612958f54a987a4ffc9ee587a2045d6" - integrity sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A== - dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - "@babel/helper-wrap-function" "^7.14.5" - "@babel/types" "^7.14.5" - -"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" - integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-simple-access@^7.14.5", "@babel/helper-simple-access@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" - integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-skip-transparent-expression-wrappers@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz#96f486ac050ca9f44b009fbe5b7d394cab3a0ee4" - integrity sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ== - dependencies: - "@babel/types" "^7.14.5" - -"@babel/helper-split-export-declaration@^7.14.5", "@babel/helper-split-export-declaration@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" - integrity sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" - integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== - -"@babel/helper-validator-option@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" - integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== - -"@babel/helper-wrap-function@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz#5919d115bf0fe328b8a5d63bcb610f51601f2bff" - integrity sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ== - dependencies: - "@babel/helper-function-name" "^7.14.5" - "@babel/template" "^7.14.5" - "@babel/traverse" "^7.14.5" - "@babel/types" "^7.14.5" - -"@babel/helpers@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" - integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== - dependencies: - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/highlight@^7.14.5", "@babel/highlight@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" - integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.5" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" - integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e" - integrity sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" - "@babel/plugin-proposal-optional-chaining" "^7.14.5" - -"@babel/plugin-proposal-async-generator-functions@^7.14.7": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz#784a48c3d8ed073f65adcf30b57bcbf6c8119ace" - integrity sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.14.5" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.14.5", "@babel/plugin-proposal-class-properties@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e" - integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-proposal-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz#158e9e10d449c3849ef3ecde94a03d9f1841b681" - integrity sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-proposal-decorators@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.14.5.tgz#59bc4dfc1d665b5a6749cf798ff42297ed1b2c1d" - integrity sha512-LYz5nvQcvYeRVjui1Ykn28i+3aUiXwQ/3MGoEy0InTaz1pJo/lAzmIDXX+BQny/oufgHzJ6vnEEiXQ8KZjEVFg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-decorators" "^7.14.5" - -"@babel/plugin-proposal-dynamic-import@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c" - integrity sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - -"@babel/plugin-proposal-export-default-from@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.14.5.tgz#8931a6560632c650f92a8e5948f6e73019d6d321" - integrity sha512-T8KZ5abXvKMjF6JcoXjgac3ElmXf0AWzJwi2O/42Jk+HmCky3D9+i1B7NPP1FblyceqTevKeV/9szeikFoaMDg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-export-default-from" "^7.14.5" - -"@babel/plugin-proposal-export-namespace-from@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz#dbad244310ce6ccd083072167d8cea83a52faf76" - integrity sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz#38de60db362e83a3d8c944ac858ddf9f0c2239eb" - integrity sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz#6e6229c2a99b02ab2915f82571e0cc646a40c738" - integrity sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.1", "@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz#ee38589ce00e2cc59b299ec3ea406fcd3a0fdaf6" - integrity sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz#83631bf33d9a51df184c2102a069ac0c58c05f18" - integrity sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@^7.14.7", "@babel/plugin-proposal-object-rest-spread@^7.9.6": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz#5920a2b3df7f7901df0205974c0641b13fd9d363" - integrity sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g== - dependencies: - "@babel/compat-data" "^7.14.7" - "@babel/helper-compilation-targets" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.14.5" - -"@babel/plugin-proposal-optional-catch-binding@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c" - integrity sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.10.1", "@babel/plugin-proposal-optional-chaining@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603" - integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-methods@^7.14.5", "@babel/plugin-proposal-private-methods@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz#37446495996b2945f30f5be5b60d5e2aa4f5792d" - integrity sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-proposal-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz#9f65a4d0493a940b4c01f8aa9d3f1894a587f636" - integrity sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q== - dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz#0f95ee0e757a5d647f378daa0eca7e93faa8bbe8" - integrity sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-decorators@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.14.5.tgz#eafb9c0cbe09c8afeb964ba3a7bbd63945a72f20" - integrity sha512-c4sZMRWL4GSvP1EXy0woIP7m4jkVcEuG8R1TOZxPBPtp4FSM/kiPZub9UIs/Jrb5ZAOzvTUSGYrWsrSu1JvoPw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-default-from@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.14.5.tgz#cdfa9d43d2b2c89b6f1af3e83518e8c8b9ed0dbc" - integrity sha512-snWDxjuaPEobRBnhpqEfZ8RMxDbHt8+87fiEioGuE+Uc0xAKgSD8QiuL3lF93hPVQfZFAcYwrrf+H5qUhike3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-flow@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.14.5.tgz#2ff654999497d7d7d142493260005263731da180" - integrity sha512-9WK5ZwKCdWHxVuU13XNT6X73FGmutAXeor5lGFq6qhOFtMFUF4jkbijuyUdZZlpYq6E2hZeZf/u3959X9wsv0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" - integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" - integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-arrow-functions@^7.14.5", "@babel/plugin-transform-arrow-functions@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a" - integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-async-to-generator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" - integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA== - dependencies: - "@babel/helper-module-imports" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.14.5" - -"@babel/plugin-transform-block-scoped-functions@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4" - integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-block-scoping@^7.14.5", "@babel/plugin-transform-block-scoping@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz#8cc63e61e50f42e078e6f09be775a75f23ef9939" - integrity sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-classes@^7.14.5", "@babel/plugin-transform-classes@^7.9.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.5.tgz#0e98e82097b38550b03b483f9b51a78de0acb2cf" - integrity sha512-J4VxKAMykM06K/64z9rwiL6xnBHgB1+FVspqvlgCdwD1KUbQNfszeKVVOMh59w3sztHYIZDgnhOC4WbdEfHFDA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - "@babel/helper-function-name" "^7.14.5" - "@babel/helper-optimise-call-expression" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" - "@babel/helper-split-export-declaration" "^7.14.5" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f" - integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-destructuring@^7.14.7", "@babel/plugin-transform-destructuring@^7.9.5": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576" - integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz#2f6bf76e46bdf8043b4e7e16cf24532629ba0c7a" - integrity sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-duplicate-keys@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954" - integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-exponentiation-operator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493" - integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-flow-strip-types@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.14.5.tgz#0dc9c1d11dcdc873417903d6df4bed019ef0f85e" - integrity sha512-KhcolBKfXbvjwI3TV7r7TkYm8oNXHNBqGOy6JDVwtecFaRoKYsUUqJdS10q0YDKW1c6aZQgO+Ys3LfGkox8pXA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-flow" "^7.14.5" - -"@babel/plugin-transform-for-of@^7.14.5", "@babel/plugin-transform-for-of@^7.9.0": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz#dae384613de8f77c196a8869cbf602a44f7fc0eb" - integrity sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-function-name@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2" - integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ== - dependencies: - "@babel/helper-function-name" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78" - integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-member-expression-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz#b39cd5212a2bf235a617d320ec2b48bcc091b8a7" - integrity sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-modules-amd@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7" - integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g== - dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-commonjs@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz#7aaee0ea98283de94da98b28f8c35701429dad97" - integrity sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A== - dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-simple-access" "^7.14.5" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-systemjs@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz#c75342ef8b30dcde4295d3401aae24e65638ed29" - integrity sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA== - dependencies: - "@babel/helper-hoist-variables" "^7.14.5" - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-identifier" "^7.14.5" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-umd@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz#fb662dfee697cce274a7cda525190a79096aa6e0" - integrity sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA== - dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.14.7": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz#60c06892acf9df231e256c24464bfecb0908fd4e" - integrity sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - -"@babel/plugin-transform-new-target@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz#31bdae8b925dc84076ebfcd2a9940143aed7dbf8" - integrity sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-object-super@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45" - integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" - -"@babel/plugin-transform-parameters@^7.14.5", "@babel/plugin-transform-parameters@^7.9.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz#49662e86a1f3ddccac6363a7dfb1ff0a158afeb3" - integrity sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-property-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz#0ddbaa1f83db3606f1cdf4846fa1dfb473458b34" - integrity sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-react-constant-elements@^7.12.1": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.14.5.tgz#41790d856f7c5cec82d2bcf5d0e5064d682522ed" - integrity sha512-NBqLEx1GxllIOXJInJAQbrnwwYJsV3WaMHIcOwD8rhYS0AabTWn7kHdHgPgu5RmHLU0q4DMxhAMu8ue/KampgQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-react-display-name@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.14.5.tgz#baa92d15c4570411301a85a74c13534873885b65" - integrity sha512-07aqY1ChoPgIxsuDviptRpVkWCSbXWmzQqcgy65C6YSFOfPFvb/DX3bBRHh7pCd/PMEEYHYWUTSVkCbkVainYQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-react-jsx-development@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.14.5.tgz#1a6c73e2f7ed2c42eebc3d2ad60b0c7494fcb9af" - integrity sha512-rdwG/9jC6QybWxVe2UVOa7q6cnTpw8JRRHOxntG/h6g/guAOe6AhtQHJuJh5FwmnXIT1bdm5vC2/5huV8ZOorQ== - dependencies: - "@babel/plugin-transform-react-jsx" "^7.14.5" - -"@babel/plugin-transform-react-jsx@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.5.tgz#39749f0ee1efd8a1bd729152cf5f78f1d247a44a" - integrity sha512-7RylxNeDnxc1OleDm0F5Q/BSL+whYRbOAR+bwgCxIr0L32v7UFh/pz1DLMZideAUxKT6eMoS2zQH6fyODLEi8Q== - dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - "@babel/helper-module-imports" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-jsx" "^7.14.5" - "@babel/types" "^7.14.5" - -"@babel/plugin-transform-react-pure-annotations@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.14.5.tgz#18de612b84021e3a9802cbc212c9d9f46d0d11fc" - integrity sha512-3X4HpBJimNxW4rhUy/SONPyNQHp5YRr0HhJdT2OH1BRp0of7u3Dkirc7x9FRJMKMqTBI079VZ1hzv7Ouuz///g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-regenerator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f" - integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg== - dependencies: - regenerator-transform "^0.14.2" - -"@babel/plugin-transform-reserved-words@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz#c44589b661cfdbef8d4300dcc7469dffa92f8304" - integrity sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-shorthand-properties@^7.14.5", "@babel/plugin-transform-shorthand-properties@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58" - integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-spread@^7.14.6", "@babel/plugin-transform-spread@^7.8.3": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144" - integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" - -"@babel/plugin-transform-sticky-regex@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9" - integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-template-literals@^7.14.5", "@babel/plugin-transform-template-literals@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93" - integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-typeof-symbol@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4" - integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-typescript@^7.15.0": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.4.tgz#db7a062dcf8be5fc096bc0eeb40a13fbfa1fa251" - integrity sha512-sM1/FEjwYjXvMwu1PJStH11kJ154zd/lpY56NQJ5qH2D0mabMv1CAy/kdvS9RP4Xgfj9fBBA3JiSLdDHgXdzOA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-typescript" "^7.14.5" - -"@babel/plugin-transform-unicode-escapes@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b" - integrity sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-unicode-regex@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e" - integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/preset-env@^7.10.2", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.9.6": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.7.tgz#5c70b22d4c2d893b03d8c886a5c17422502b932a" - integrity sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA== - dependencies: - "@babel/compat-data" "^7.14.7" - "@babel/helper-compilation-targets" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5" - "@babel/plugin-proposal-async-generator-functions" "^7.14.7" - "@babel/plugin-proposal-class-properties" "^7.14.5" - "@babel/plugin-proposal-class-static-block" "^7.14.5" - "@babel/plugin-proposal-dynamic-import" "^7.14.5" - "@babel/plugin-proposal-export-namespace-from" "^7.14.5" - "@babel/plugin-proposal-json-strings" "^7.14.5" - "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" - "@babel/plugin-proposal-numeric-separator" "^7.14.5" - "@babel/plugin-proposal-object-rest-spread" "^7.14.7" - "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" - "@babel/plugin-proposal-optional-chaining" "^7.14.5" - "@babel/plugin-proposal-private-methods" "^7.14.5" - "@babel/plugin-proposal-private-property-in-object" "^7.14.5" - "@babel/plugin-proposal-unicode-property-regex" "^7.14.5" - "@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.14.5" - "@babel/plugin-transform-async-to-generator" "^7.14.5" - "@babel/plugin-transform-block-scoped-functions" "^7.14.5" - "@babel/plugin-transform-block-scoping" "^7.14.5" - "@babel/plugin-transform-classes" "^7.14.5" - "@babel/plugin-transform-computed-properties" "^7.14.5" - "@babel/plugin-transform-destructuring" "^7.14.7" - "@babel/plugin-transform-dotall-regex" "^7.14.5" - "@babel/plugin-transform-duplicate-keys" "^7.14.5" - "@babel/plugin-transform-exponentiation-operator" "^7.14.5" - "@babel/plugin-transform-for-of" "^7.14.5" - "@babel/plugin-transform-function-name" "^7.14.5" - "@babel/plugin-transform-literals" "^7.14.5" - "@babel/plugin-transform-member-expression-literals" "^7.14.5" - "@babel/plugin-transform-modules-amd" "^7.14.5" - "@babel/plugin-transform-modules-commonjs" "^7.14.5" - "@babel/plugin-transform-modules-systemjs" "^7.14.5" - "@babel/plugin-transform-modules-umd" "^7.14.5" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.7" - "@babel/plugin-transform-new-target" "^7.14.5" - "@babel/plugin-transform-object-super" "^7.14.5" - "@babel/plugin-transform-parameters" "^7.14.5" - "@babel/plugin-transform-property-literals" "^7.14.5" - "@babel/plugin-transform-regenerator" "^7.14.5" - "@babel/plugin-transform-reserved-words" "^7.14.5" - "@babel/plugin-transform-shorthand-properties" "^7.14.5" - "@babel/plugin-transform-spread" "^7.14.6" - "@babel/plugin-transform-sticky-regex" "^7.14.5" - "@babel/plugin-transform-template-literals" "^7.14.5" - "@babel/plugin-transform-typeof-symbol" "^7.14.5" - "@babel/plugin-transform-unicode-escapes" "^7.14.5" - "@babel/plugin-transform-unicode-regex" "^7.14.5" - "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.14.5" - babel-plugin-polyfill-corejs2 "^0.2.2" - babel-plugin-polyfill-corejs3 "^0.2.2" - babel-plugin-polyfill-regenerator "^0.2.2" - core-js-compat "^3.15.0" - semver "^6.3.0" - -"@babel/preset-flow@^7.0.0": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.14.5.tgz#a1810b0780c8b48ab0bece8e7ab8d0d37712751c" - integrity sha512-pP5QEb4qRUSVGzzKx9xqRuHUrM/jEzMqdrZpdMA+oUCRgd5zM1qGr5y5+ZgAL/1tVv1H0dyk5t4SKJntqyiVtg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-flow-strip-types" "^7.14.5" - -"@babel/preset-modules@^0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" - integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== - 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" - -"@babel/preset-react@^7.0.0", "@babel/preset-react@^7.12.5", "@babel/preset-react@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.14.5.tgz#0fbb769513f899c2c56f3a882fa79673c2d4ab3c" - integrity sha512-XFxBkjyObLvBaAvkx1Ie95Iaq4S/GUEIrejyrntQ/VCMKUYvKLoyKxOBzJ2kjA3b6rC9/KL6KXfDC2GqvLiNqQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-react-display-name" "^7.14.5" - "@babel/plugin-transform-react-jsx" "^7.14.5" - "@babel/plugin-transform-react-jsx-development" "^7.14.5" - "@babel/plugin-transform-react-pure-annotations" "^7.14.5" - -"@babel/preset-typescript@^7.9.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz#e8fca638a1a0f64f14e1119f7fe4500277840945" - integrity sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-typescript" "^7.15.0" - -"@babel/register@^7.10.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.14.5.tgz#d0eac615065d9c2f1995842f85d6e56c345f3233" - integrity sha512-TjJpGz/aDjFGWsItRBQMOFTrmTI9tr79CHOK+KIvLeCkbxuOAk2M5QHjvruIMGoo9OuccMh5euplPzc5FjAKGg== - dependencies: - clone-deep "^4.0.1" - find-cache-dir "^2.0.0" - make-dir "^2.1.0" - pirates "^4.0.0" - source-map-support "^0.5.16" - -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d" - integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.15.4": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" - integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== - dependencies: - regenerator-runtime "^0.13.11" - -"@babel/template@^7.14.5", "@babel/template@^7.15.4", "@babel/template@^7.3.3": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" - integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" - 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" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.14.5", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" - integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== - dependencies: - "@babel/helper-validator-identifier" "^7.14.9" - to-fast-properties "^2.0.0" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@blueprintjs/core@^3.36.0", "@blueprintjs/core@^3.46.0": - version "3.46.0" - resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-3.46.0.tgz#fde92406ed97d48c949d5fe5578e7880efdf7577" - integrity sha512-kcYrisJMz7jPIuTc9AwFAbHMmmP/BxM2CC3e8vLaLk5h+xtXVzRipx19GA6ysSdguYXOnCPETwM6421QLehCCw== - dependencies: - "@blueprintjs/icons" "^3.27.0" - "@types/dom4" "^2.0.1" - classnames "^2.2" - dom4 "^2.1.5" - normalize.css "^8.0.1" - popper.js "^1.16.1" - react-lifecycles-compat "^3.0.4" - react-popper "^1.3.7" - react-transition-group "^2.9.0" - resize-observer-polyfill "^1.5.1" - tslib "~1.13.0" - -"@blueprintjs/icons@^3.27.0": - version "3.27.0" - resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-3.27.0.tgz#f4c03e8bc2f9310f7eaefaab26dd91f65935da43" - integrity sha512-ItRioyrr2s70chclj5q38HS9omKOa15b3JZXv9JcMIFz+6w6rAcoAH7DA+5xIs27bFjax/SdAZp/eYXSw0+QpA== - dependencies: - classnames "^2.2" - tslib "~1.13.0" - -"@blueprintjs/select@^3.15.0": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@blueprintjs/select/-/select-3.16.5.tgz#31b15a606dafd15643aa539d93d74795ec2aabe4" - integrity sha512-+DJF7Fy11NjV1mUBHtEyx4fQTZDBki8NxxTZLsQWD6lGnUkZQDWToWmkr3oDC1+4MFG++Hf0nKvdp48FqY44IA== - dependencies: - "@blueprintjs/core" "^3.46.0" - classnames "^2.2" - tslib "~1.13.0" - -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - -"@discoveryjs/json-ext@^0.5.0": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d" - integrity sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g== - -"@emotion/cache@^10.0.27": - version "10.0.29" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" - integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ== - dependencies: - "@emotion/sheet" "0.9.4" - "@emotion/stylis" "0.8.5" - "@emotion/utils" "0.11.3" - "@emotion/weak-memoize" "0.2.5" - -"@emotion/core@^10.0.20": - version "10.1.1" - resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3" - integrity sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA== - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/cache" "^10.0.27" - "@emotion/css" "^10.0.27" - "@emotion/serialize" "^0.11.15" - "@emotion/sheet" "0.9.4" - "@emotion/utils" "0.11.3" - -"@emotion/css@^10.0.27": - version "10.0.27" - resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" - integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw== - dependencies: - "@emotion/serialize" "^0.11.15" - "@emotion/utils" "0.11.3" - babel-plugin-emotion "^10.0.27" - -"@emotion/hash@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== - -"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.6": - version "0.8.8" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== - dependencies: - "@emotion/memoize" "0.7.4" - -"@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== - -"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": - version "0.11.16" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" - integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg== - dependencies: - "@emotion/hash" "0.8.0" - "@emotion/memoize" "0.7.4" - "@emotion/unitless" "0.7.5" - "@emotion/utils" "0.11.3" - csstype "^2.5.7" - -"@emotion/sheet@0.9.4": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" - integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== - -"@emotion/styled-base@^10.0.27": - version "10.0.31" - resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.31.tgz#940957ee0aa15c6974adc7d494ff19765a2f742a" - integrity sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ== - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/is-prop-valid" "0.8.8" - "@emotion/serialize" "^0.11.15" - "@emotion/utils" "0.11.3" - -"@emotion/styled@^10.0.17": - version "10.0.27" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.27.tgz#12cb67e91f7ad7431e1875b1d83a94b814133eaf" - integrity sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q== - dependencies: - "@emotion/styled-base" "^10.0.27" - babel-plugin-emotion "^10.0.27" - -"@emotion/stylis@0.8.5": - version "0.8.5" - resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" - integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== - -"@emotion/unitless@0.7.5": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== - -"@emotion/utils@0.11.3": - version "0.11.3" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" - integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== - -"@emotion/weak-memoize@0.2.5": - version "0.2.5" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" - integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== - -"@eslint/eslintrc@^0.2.1": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" - integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== - dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - lodash "^4.17.19" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@fortawesome/fontawesome-free@^5.12.0": - version "5.15.3" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.3.tgz#c36ffa64a2a239bf948541a97b6ae8d729e09a9a" - integrity sha512-rFnSUN/QOtnOAgqFRooTA3H57JLDm0QEG/jPdk+tLQNL/eWd+Aok8g3qCI+Q1xuDPWpGW/i9JySpJVsq8Q0s9w== - -"@gar/promisify@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" - integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== - -"@hutson/parse-repository-url@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" - integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== - -"@hypnosphi/create-react-context@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz#f8bfebdc7665f5d426cba3753e0e9c7d3154d7c6" - integrity sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A== - dependencies: - gud "^1.0.0" - warning "^4.0.3" - -"@icons/material@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" - integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - 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" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" - integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== - 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" - -"@jest/core@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" - integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== - 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" - -"@jest/environment@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" - integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== - dependencies: - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - -"@jest/fake-timers@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" - integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== - 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" - -"@jest/globals@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" - integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/types" "^26.6.2" - expect "^26.6.2" - -"@jest/reporters@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" - integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== - 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" - optionalDependencies: - node-notifier "^8.0.0" - -"@jest/source-map@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" - integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" - -"@jest/test-result@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" - integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== - dependencies: - "@jest/console" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" - integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== - 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" - -"@jest/transform@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" - integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== - 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" - -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - 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" - -"@jupyter/ydoc@~0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@jupyter/ydoc/-/ydoc-0.2.4.tgz#bc312f171777b58e286aadca62dadeca3a894dd1" - integrity sha512-QACcB4bF+Ew4UJmJP+3OyiyQm3vwRYF6iZCQK9q0nE2U5uAosQkfLyT6Bx71jPUXe4G9lEF6m9fjpZvSUX7Lyw== - dependencies: - "@jupyterlab/nbformat" "^3.0.0 || ^4.0.0-alpha.15" - "@lumino/coreutils" "^1.11.0 || ^2.0.0-alpha.6" - "@lumino/disposable" "^1.10.0 || ^2.0.0-alpha.6" - "@lumino/signaling" "^1.10.0 || ^2.0.0-alpha.6" - y-protocols "^1.0.5" - yjs "^13.5.40" - -"@lerna/add@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" - integrity sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng== - dependencies: - "@lerna/bootstrap" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - npm-package-arg "^8.1.0" - p-map "^4.0.0" - pacote "^11.2.6" - semver "^7.3.4" - -"@lerna/bootstrap@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-4.0.0.tgz#5f5c5e2c6cfc8fcec50cb2fbe569a8c607101891" - integrity sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/has-npm-version" "4.0.0" - "@lerna/npm-install" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/rimraf-dir" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/symlink-binary" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - get-port "^5.1.1" - multimatch "^5.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - p-map "^4.0.0" - p-map-series "^2.1.0" - p-waterfall "^2.1.1" - read-package-tree "^5.3.1" - semver "^7.3.4" - -"@lerna/changed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-4.0.0.tgz#b9fc76cea39b9292a6cd263f03eb57af85c9270b" - integrity sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ== - dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" - -"@lerna/check-working-tree@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz#257e36a602c00142e76082a19358e3e1ae8dbd58" - integrity sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q== - dependencies: - "@lerna/collect-uncommitted" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/validation-error" "4.0.0" - -"@lerna/child-process@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-4.0.0.tgz#341b96a57dffbd9705646d316e231df6fa4df6e1" - integrity sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q== - dependencies: - chalk "^4.1.0" - execa "^5.0.0" - strong-log-transformer "^2.1.0" - -"@lerna/clean@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-4.0.0.tgz#8f778b6f2617aa2a936a6b5e085ae62498e57dc5" - integrity sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/rimraf-dir" "4.0.0" - p-map "^4.0.0" - p-map-series "^2.1.0" - p-waterfall "^2.1.1" - -"@lerna/cli@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-4.0.0.tgz#8eabd334558836c1664df23f19acb95e98b5bbf3" - integrity sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA== - dependencies: - "@lerna/global-options" "4.0.0" - dedent "^0.7.0" - npmlog "^4.1.2" - yargs "^16.2.0" - -"@lerna/collect-uncommitted@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz#855cd64612969371cfc2453b90593053ff1ba779" - integrity sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g== - dependencies: - "@lerna/child-process" "4.0.0" - chalk "^4.1.0" - npmlog "^4.1.2" - -"@lerna/collect-updates@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-4.0.0.tgz#8e208b1bafd98a372ff1177f7a5e288f6bea8041" - integrity sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/describe-ref" "4.0.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - slash "^3.0.0" - -"@lerna/command@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/command/-/command-4.0.0.tgz#991c7971df8f5bf6ae6e42c808869a55361c1b98" - integrity sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/project" "4.0.0" - "@lerna/validation-error" "4.0.0" - "@lerna/write-log-file" "4.0.0" - clone-deep "^4.0.1" - dedent "^0.7.0" - execa "^5.0.0" - is-ci "^2.0.0" - npmlog "^4.1.2" - -"@lerna/conventional-commits@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz#660fb2c7b718cb942ead70110df61f18c6f99750" - integrity sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw== - dependencies: - "@lerna/validation-error" "4.0.0" - conventional-changelog-angular "^5.0.12" - conventional-changelog-core "^4.2.2" - conventional-recommended-bump "^6.1.0" - fs-extra "^9.1.0" - get-stream "^6.0.0" - lodash.template "^4.5.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - pify "^5.0.0" - semver "^7.3.4" - -"@lerna/create-symlink@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-4.0.0.tgz#8c5317ce5ae89f67825443bd7651bf4121786228" - integrity sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig== - dependencies: - cmd-shim "^4.1.0" - fs-extra "^9.1.0" - npmlog "^4.1.2" - -"@lerna/create@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-4.0.0.tgz#b6947e9b5dfb6530321952998948c3e63d64d730" - integrity sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - fs-extra "^9.1.0" - globby "^11.0.2" - init-package-json "^2.0.2" - npm-package-arg "^8.1.0" - p-reduce "^2.1.0" - pacote "^11.2.6" - pify "^5.0.0" - semver "^7.3.4" - slash "^3.0.0" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" - whatwg-url "^8.4.0" - yargs-parser "20.2.4" - -"@lerna/describe-ref@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-4.0.0.tgz#53c53b4ea65fdceffa072a62bfebe6772c45d9ec" - integrity sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ== - dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" - -"@lerna/diff@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-4.0.0.tgz#6d3071817aaa4205a07bf77cfc6e932796d48b92" - integrity sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/validation-error" "4.0.0" - npmlog "^4.1.2" - -"@lerna/exec@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-4.0.0.tgz#eb6cb95cb92d42590e9e2d628fcaf4719d4a8be6" - integrity sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/profiler" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - p-map "^4.0.0" - -"@lerna/filter-options@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-4.0.0.tgz#ac94cc515d7fa3b47e2f7d74deddeabb1de5e9e6" - integrity sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw== - dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/filter-packages" "4.0.0" - dedent "^0.7.0" - npmlog "^4.1.2" - -"@lerna/filter-packages@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-4.0.0.tgz#b1f70d70e1de9cdd36a4e50caa0ac501f8d012f2" - integrity sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA== - dependencies: - "@lerna/validation-error" "4.0.0" - multimatch "^5.0.0" - npmlog "^4.1.2" - -"@lerna/get-npm-exec-opts@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz#dc955be94a4ae75c374ef9bce91320887d34608f" - integrity sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ== - dependencies: - npmlog "^4.1.2" - -"@lerna/get-packed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-4.0.0.tgz#0989d61624ac1f97e393bdad2137c49cd7a37823" - integrity sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w== - dependencies: - fs-extra "^9.1.0" - ssri "^8.0.1" - tar "^6.1.0" - -"@lerna/github-client@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-4.0.0.tgz#2ced67721363ef70f8e12ffafce4410918f4a8a4" - integrity sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw== - dependencies: - "@lerna/child-process" "4.0.0" - "@octokit/plugin-enterprise-rest" "^6.0.1" - "@octokit/rest" "^18.1.0" - git-url-parse "^11.4.4" - npmlog "^4.1.2" - -"@lerna/gitlab-client@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz#00dad73379c7b38951d4b4ded043504c14e2b67d" - integrity sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA== - dependencies: - node-fetch "^2.6.1" - npmlog "^4.1.2" - whatwg-url "^8.4.0" - -"@lerna/global-options@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-4.0.0.tgz#c7d8b0de6a01d8a845e2621ea89e7f60f18c6a5f" - integrity sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ== - -"@lerna/has-npm-version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz#d3fc3292c545eb28bd493b36e6237cf0279f631c" - integrity sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg== - dependencies: - "@lerna/child-process" "4.0.0" - semver "^7.3.4" - -"@lerna/import@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/import/-/import-4.0.0.tgz#bde656c4a451fa87ae41733ff8a8da60547c5465" - integrity sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - fs-extra "^9.1.0" - p-map-series "^2.1.0" - -"@lerna/info@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/info/-/info-4.0.0.tgz#b9fb0e479d60efe1623603958a831a88b1d7f1fc" - integrity sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/output" "4.0.0" - envinfo "^7.7.4" - -"@lerna/init@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/init/-/init-4.0.0.tgz#dadff67e6dfb981e8ccbe0e6a310e837962f6c7a" - integrity sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - write-json-file "^4.3.0" - -"@lerna/link@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/link/-/link-4.0.0.tgz#c3a38aabd44279d714e90f2451e31b63f0fb65ba" - integrity sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" - p-map "^4.0.0" - slash "^3.0.0" - -"@lerna/list@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/list/-/list-4.0.0.tgz#24b4e6995bd73f81c556793fe502b847efd9d1d7" - integrity sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" - -"@lerna/listable@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-4.0.0.tgz#d00d6cb4809b403f2b0374fc521a78e318b01214" - integrity sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ== - dependencies: - "@lerna/query-graph" "4.0.0" - chalk "^4.1.0" - columnify "^1.5.4" - -"@lerna/log-packed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-4.0.0.tgz#95168fe2e26ac6a71e42f4be857519b77e57a09f" - integrity sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ== - dependencies: - byte-size "^7.0.0" - columnify "^1.5.4" - has-unicode "^2.0.1" - npmlog "^4.1.2" - -"@lerna/npm-conf@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-4.0.0.tgz#b259fd1e1cee2bf5402b236e770140ff9ade7fd2" - integrity sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw== - dependencies: - config-chain "^1.1.12" - pify "^5.0.0" - -"@lerna/npm-dist-tag@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz#d1e99b4eccd3414142f0548ad331bf2d53f3257a" - integrity sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw== - dependencies: - "@lerna/otplease" "4.0.0" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" - -"@lerna/npm-install@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-4.0.0.tgz#31180be3ab3b7d1818a1a0c206aec156b7094c78" - integrity sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" - fs-extra "^9.1.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - signal-exit "^3.0.3" - write-pkg "^4.0.0" - -"@lerna/npm-publish@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-4.0.0.tgz#84eb62e876fe949ae1fd62c60804423dbc2c4472" - integrity sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w== - dependencies: - "@lerna/otplease" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - fs-extra "^9.1.0" - libnpmpublish "^4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - pify "^5.0.0" - read-package-json "^3.0.0" - -"@lerna/npm-run-script@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz#dfebf4f4601442e7c0b5214f9fb0d96c9350743b" - integrity sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" - npmlog "^4.1.2" - -"@lerna/otplease@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/otplease/-/otplease-4.0.0.tgz#84972eb43448f8a1077435ba1c5e59233b725850" - integrity sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw== - dependencies: - "@lerna/prompt" "4.0.0" - -"@lerna/output@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/output/-/output-4.0.0.tgz#b1d72215c0e35483e4f3e9994debc82c621851f2" - integrity sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w== - dependencies: - npmlog "^4.1.2" - -"@lerna/pack-directory@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-4.0.0.tgz#8b617db95d20792f043aaaa13a9ccc0e04cb4c74" - integrity sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ== - dependencies: - "@lerna/get-packed" "4.0.0" - "@lerna/package" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - npm-packlist "^2.1.4" - npmlog "^4.1.2" - tar "^6.1.0" - temp-write "^4.0.0" - -"@lerna/package-graph@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-4.0.0.tgz#16a00253a8ac810f72041481cb46bcee8d8123dd" - integrity sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw== - dependencies: - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/validation-error" "4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - semver "^7.3.4" - -"@lerna/package@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/package/-/package-4.0.0.tgz#1b4c259c4bcff45c876ee1d591a043aacbc0d6b7" - integrity sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q== - dependencies: - load-json-file "^6.2.0" - npm-package-arg "^8.1.0" - write-pkg "^4.0.0" - -"@lerna/prerelease-id-from-version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz#c7e0676fcee1950d85630e108eddecdd5b48c916" - integrity sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg== - dependencies: - semver "^7.3.4" - -"@lerna/profiler@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/profiler/-/profiler-4.0.0.tgz#8a53ab874522eae15d178402bff90a14071908e9" - integrity sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q== - dependencies: - fs-extra "^9.1.0" - npmlog "^4.1.2" - upath "^2.0.1" - -"@lerna/project@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/project/-/project-4.0.0.tgz#ff84893935833533a74deff30c0e64ddb7f0ba6b" - integrity sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg== - dependencies: - "@lerna/package" "4.0.0" - "@lerna/validation-error" "4.0.0" - cosmiconfig "^7.0.0" - dedent "^0.7.0" - dot-prop "^6.0.1" - glob-parent "^5.1.1" - globby "^11.0.2" - load-json-file "^6.2.0" - npmlog "^4.1.2" - p-map "^4.0.0" - resolve-from "^5.0.0" - write-json-file "^4.3.0" - -"@lerna/prompt@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-4.0.0.tgz#5ec69a803f3f0db0ad9f221dad64664d3daca41b" - integrity sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ== - dependencies: - inquirer "^7.3.3" - npmlog "^4.1.2" - -"@lerna/publish@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-4.0.0.tgz#f67011305adeba120066a3b6d984a5bb5fceef65" - integrity sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg== - dependencies: - "@lerna/check-working-tree" "4.0.0" - "@lerna/child-process" "4.0.0" - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/log-packed" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/npm-dist-tag" "4.0.0" - "@lerna/npm-publish" "4.0.0" - "@lerna/otplease" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/pack-directory" "4.0.0" - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - "@lerna/version" "4.0.0" - fs-extra "^9.1.0" - libnpmaccess "^4.0.1" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" - p-map "^4.0.0" - p-pipe "^3.1.0" - pacote "^11.2.6" - semver "^7.3.4" - -"@lerna/pulse-till-done@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz#04bace7d483a8205c187b806bcd8be23d7bb80a3" - integrity sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg== - dependencies: - npmlog "^4.1.2" - -"@lerna/query-graph@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/query-graph/-/query-graph-4.0.0.tgz#09dd1c819ac5ee3f38db23931143701f8a6eef63" - integrity sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg== - dependencies: - "@lerna/package-graph" "4.0.0" - -"@lerna/resolve-symlink@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz#6d006628a210c9b821964657a9e20a8c9a115e14" - integrity sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA== - dependencies: - fs-extra "^9.1.0" - npmlog "^4.1.2" - read-cmd-shim "^2.0.0" - -"@lerna/rimraf-dir@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz#2edf3b62d4eb0ef4e44e430f5844667d551ec25a" - integrity sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg== - dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" - path-exists "^4.0.0" - rimraf "^3.0.2" - -"@lerna/run-lifecycle@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz#e648a46f9210a9bcd7c391df6844498cb5079334" - integrity sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ== - dependencies: - "@lerna/npm-conf" "4.0.0" - npm-lifecycle "^3.1.5" - npmlog "^4.1.2" - -"@lerna/run-topologically@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-topologically/-/run-topologically-4.0.0.tgz#af846eeee1a09b0c2be0d1bfb5ef0f7b04bb1827" - integrity sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA== - dependencies: - "@lerna/query-graph" "4.0.0" - p-queue "^6.6.2" - -"@lerna/run@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run/-/run-4.0.0.tgz#4bc7fda055a729487897c23579694f6183c91262" - integrity sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/npm-run-script" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/profiler" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/timer" "4.0.0" - "@lerna/validation-error" "4.0.0" - p-map "^4.0.0" - -"@lerna/symlink-binary@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz#21009f62d53a425f136cb4c1a32c6b2a0cc02d47" - integrity sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA== - dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/package" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - -"@lerna/symlink-dependencies@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz#8910eca084ae062642d0490d8972cf2d98e9ebbd" - integrity sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw== - dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/resolve-symlink" "4.0.0" - "@lerna/symlink-binary" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - p-map-series "^2.1.0" - -"@lerna/timer@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-4.0.0.tgz#a52e51bfcd39bfd768988049ace7b15c1fd7a6da" - integrity sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg== - -"@lerna/validation-error@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-4.0.0.tgz#af9d62fe8304eaa2eb9a6ba1394f9aa807026d35" - integrity sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw== - dependencies: - npmlog "^4.1.2" - -"@lerna/version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-4.0.0.tgz#532659ec6154d8a8789c5ab53878663e244e3228" - integrity sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA== - dependencies: - "@lerna/check-working-tree" "4.0.0" - "@lerna/child-process" "4.0.0" - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/conventional-commits" "4.0.0" - "@lerna/github-client" "4.0.0" - "@lerna/gitlab-client" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - chalk "^4.1.0" - dedent "^0.7.0" - load-json-file "^6.2.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - p-map "^4.0.0" - p-pipe "^3.1.0" - p-reduce "^2.1.0" - p-waterfall "^2.1.1" - semver "^7.3.4" - slash "^3.0.0" - temp-write "^4.0.0" - write-json-file "^4.3.0" - -"@lerna/write-log-file@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-4.0.0.tgz#18221a38a6a307d6b0a5844dd592ad53fa27091e" - integrity sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg== - dependencies: - npmlog "^4.1.2" - write-file-atomic "^3.0.3" - -"@lumino/algorithm@^1.9.0", "@lumino/algorithm@^1.9.2": - version "1.9.2" - resolved "https://registry.yarnpkg.com/@lumino/algorithm/-/algorithm-1.9.2.tgz#b95e6419aed58ff6b863a51bfb4add0f795141d3" - integrity sha512-Z06lp/yuhz8CtIir3PNTGnuk7909eXt4ukJsCzChsGuot2l5Fbs96RJ/FOHgwCedaX74CtxPjXHXoszFbUA+4A== - -"@lumino/application@^1.31.4": - version "1.31.4" - resolved "https://registry.yarnpkg.com/@lumino/application/-/application-1.31.4.tgz#b804fcc46fb77deb41aee94c48bea990f735d6b9" - integrity sha512-dOSsDJ1tXOxC3fnSHvtDQK5RcICLEVPtO19HeCGwurb5W2ZZ55SZT2b5jZu6V/v8lGdtkNbr1RJltRpJRSRb/A== - dependencies: - "@lumino/commands" "^1.21.1" - "@lumino/coreutils" "^1.12.1" - "@lumino/widgets" "^1.37.2" - -"@lumino/collections@^1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@lumino/collections/-/collections-1.9.3.tgz#370dc2d50aa91371288a4f7376bea5a3191fc5dc" - integrity sha512-2i2Wf1xnfTgEgdyKEpqM16bcYRIhUOGCDzaVCEZACVG9R1CgYwOe3zfn71slBQOVSjjRgwYrgLXu4MBpt6YK+g== - dependencies: - "@lumino/algorithm" "^1.9.2" - -"@lumino/commands@^1.19.0", "@lumino/commands@^1.21.1": - version "1.21.1" - resolved "https://registry.yarnpkg.com/@lumino/commands/-/commands-1.21.1.tgz#eda8b3cf5ef73b9c8ce93b3b5cf66bb053df2a76" - integrity sha512-d1zJmwz5bHU0BM/Rl3tRdZ7/WgXnFB0bM7x7Bf0XDlmX++jnU9k0j3mh6/5JqCGLmIApKCRwVqSaV7jPmSJlcQ== - dependencies: - "@lumino/algorithm" "^1.9.2" - "@lumino/coreutils" "^1.12.1" - "@lumino/disposable" "^1.10.4" - "@lumino/domutils" "^1.8.2" - "@lumino/keyboard" "^1.8.2" - "@lumino/signaling" "^1.11.1" - "@lumino/virtualdom" "^1.14.3" - -"@lumino/coreutils@^1.11.0", "@lumino/coreutils@^1.11.0 || ^2.0.0-alpha.6", "@lumino/coreutils@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@lumino/coreutils/-/coreutils-1.12.1.tgz#79860c9937483ddf6cda87f6c2b9da8eb1a5d768" - integrity sha512-JLu3nTHzJk9N8ohZ85u75YxemMrmDzJdNgZztfP7F7T7mxND3YVNCkJG35a6aJ7edu1sIgCjBxOvV+hv27iYvQ== - -"@lumino/datagrid@^0.36.7": - version "0.36.9" - resolved "https://registry.yarnpkg.com/@lumino/datagrid/-/datagrid-0.36.9.tgz#f28973e148b1ca92dae54e920bb92d522f551d82" - integrity sha512-qXk2IuUq31xbIYIP6HCy/taydkB/6s2cFPBuuLpAtBnAGO3VNUTI+2KYrsqTZV4odnbH1i0LKoYIpIgiDKs3Qg== - dependencies: - "@lumino/algorithm" "^1.9.2" - "@lumino/coreutils" "^1.12.1" - "@lumino/disposable" "^1.10.4" - "@lumino/domutils" "^1.8.2" - "@lumino/dragdrop" "^1.14.5" - "@lumino/keyboard" "^1.8.2" - "@lumino/messaging" "^1.10.3" - "@lumino/signaling" "^1.11.1" - "@lumino/widgets" "^1.37.2" - -"@lumino/disposable@^1.10.0", "@lumino/disposable@^1.10.0 || ^2.0.0-alpha.6", "@lumino/disposable@^1.10.4": - version "1.10.4" - resolved "https://registry.yarnpkg.com/@lumino/disposable/-/disposable-1.10.4.tgz#73b452044fecf988d7fa73fac9451b1a7f987323" - integrity sha512-4ZxyYcyzUS+ZeB2KAH9oAH3w0DUUceiVr+FIZHZ2TAYGWZI/85WlqJtfm0xjwEpCwLLW1TDqJrISuZu3iMmVMA== - dependencies: - "@lumino/algorithm" "^1.9.2" - "@lumino/signaling" "^1.11.1" - -"@lumino/domutils@^1.8.0", "@lumino/domutils@^1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@lumino/domutils/-/domutils-1.8.2.tgz#d15cdbae12bea52852bbc13c4629360f9f05b7f5" - integrity sha512-QIpMfkPJrs4GrWBuJf2Sn1fpyVPmvqUUAeD8xAQo8+4V5JAT0vUDLxZ9HijefMgNCi3+Bs8Z3lQwRCrz+cFP1A== - -"@lumino/dragdrop@^1.13.0", "@lumino/dragdrop@^1.14.5": - version "1.14.5" - resolved "https://registry.yarnpkg.com/@lumino/dragdrop/-/dragdrop-1.14.5.tgz#1db76c8a01f74cb1b0428db6234e820bb58b93ba" - integrity sha512-LC5xB82+xGF8hFyl716TMpV32OIMIMl+s3RU1PaqDkD6B7PkgiVk6NkJ4X9/GcEvl2igkvlGQt/3L7qxDAJNxw== - dependencies: - "@lumino/coreutils" "^1.12.1" - "@lumino/disposable" "^1.10.4" - -"@lumino/keyboard@^1.8.1", "@lumino/keyboard@^1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@lumino/keyboard/-/keyboard-1.8.2.tgz#714dbe671f0718f516d1ec23188b31a9ccd82fb2" - integrity sha512-Dy+XqQ1wXbcnuYtjys5A0pAqf4SpAFl9NY6owyIhXAo0Va7w3LYp3jgiP1xAaBAwMuUppiUAfrbjrysZuZ625g== - -"@lumino/messaging@^1.10.0", "@lumino/messaging@^1.10.3": - version "1.10.3" - resolved "https://registry.yarnpkg.com/@lumino/messaging/-/messaging-1.10.3.tgz#b6227bdfc178a8542571625ecb68063691b6af3c" - integrity sha512-F/KOwMCdqvdEG8CYAJcBSadzp6aI7a47Fr60zAKGqZATSRRRV41q53iXU7HjFPqQqQIvdn9Z7J32rBEAyQAzww== - dependencies: - "@lumino/algorithm" "^1.9.2" - "@lumino/collections" "^1.9.3" - -"@lumino/polling@^1.9.0": - version "1.11.4" - resolved "https://registry.yarnpkg.com/@lumino/polling/-/polling-1.11.4.tgz#ddfe47da5b41af4cfa474898542c099e445c0e6c" - integrity sha512-yC7JLssj3mqVK6TsYj7dg4AG0rcsC42YtpoDLtz9yzO84Q5flQUfmjAPQB6oPA6wZOlISs3iasF+uO2w1ls5jg== - dependencies: - "@lumino/coreutils" "^1.12.1" - "@lumino/disposable" "^1.10.4" - "@lumino/signaling" "^1.11.1" - -"@lumino/properties@^1.8.0", "@lumino/properties@^1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@lumino/properties/-/properties-1.8.2.tgz#91131f2ca91a902faa138771eb63341db78fc0fd" - integrity sha512-EkjI9Cw8R0U+xC9HxdFSu7X1tz1H1vKu20cGvJ2gU+CXlMB1DvoYJCYxCThByHZ+kURTAap4SE5x8HvKwNPbig== - -"@lumino/signaling@^1.10.0", "@lumino/signaling@^1.10.0 || ^2.0.0-alpha.6", "@lumino/signaling@^1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@lumino/signaling/-/signaling-1.11.1.tgz#438f447a1b644fd286549804f9851b5aec9679a2" - integrity sha512-YCUmgw08VoyMN5KxzqPO3KMx+cwdPv28tAN06C0K7Q/dQf+oufb1XocuhZb5selTrTmmuXeizaYxgLIQGdS1fA== - dependencies: - "@lumino/algorithm" "^1.9.2" - "@lumino/properties" "^1.8.2" - -"@lumino/virtualdom@^1.14.0", "@lumino/virtualdom@^1.14.3": - version "1.14.3" - resolved "https://registry.yarnpkg.com/@lumino/virtualdom/-/virtualdom-1.14.3.tgz#e490c36ff506d877cf45771d6968e3e26a8919fd" - integrity sha512-5joUC1yuxeXbpfbSBm/OR8Mu9HoTo6PDX0RKqzlJ9o97iml7zayFN/ynzcxScKGQAo9iaXOY8uVIvGUT8FnsGw== - dependencies: - "@lumino/algorithm" "^1.9.2" - -"@lumino/widgets@^1.37.2": - version "1.37.2" - resolved "https://registry.yarnpkg.com/@lumino/widgets/-/widgets-1.37.2.tgz#b408fae221ecec2f1b028607782fbe1e82588bce" - integrity sha512-NHKu1NBDo6ETBDoNrqSkornfUCwc8EFFzw6+LWBfYVxn2PIwciq2SdiJGEyNqL+0h/A9eVKb5ui5z4cwpRekmQ== - dependencies: - "@lumino/algorithm" "^1.9.2" - "@lumino/commands" "^1.21.1" - "@lumino/coreutils" "^1.12.1" - "@lumino/disposable" "^1.10.4" - "@lumino/domutils" "^1.8.2" - "@lumino/dragdrop" "^1.14.5" - "@lumino/keyboard" "^1.8.2" - "@lumino/messaging" "^1.10.3" - "@lumino/properties" "^1.8.2" - "@lumino/signaling" "^1.11.1" - "@lumino/virtualdom" "^1.14.3" - -"@mapbox/node-pre-gyp@^1.0.0": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz#2a0b32fcb416fb3f2250fd24cb2a81421a4f5950" - integrity sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA== - dependencies: - detect-libc "^1.0.3" - https-proxy-agent "^5.0.0" - make-dir "^3.1.0" - node-fetch "^2.6.1" - nopt "^5.0.0" - npmlog "^4.1.2" - rimraf "^3.0.2" - semver "^7.3.4" - tar "^6.1.0" - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@npmcli/ci-detect@^1.0.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" - integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== - -"@npmcli/fs@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f" - integrity sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ== - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - -"@npmcli/git@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" - integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== - dependencies: - "@npmcli/promise-spawn" "^1.3.2" - lru-cache "^6.0.0" - mkdirp "^1.0.4" - npm-pick-manifest "^6.1.1" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^2.0.2" - -"@npmcli/installed-package-contents@^1.0.6": - version "1.0.7" - resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" - integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== - dependencies: - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" - -"@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - -"@npmcli/node-gyp@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" - integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== - -"@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" - integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== - dependencies: - infer-owner "^1.0.4" - -"@npmcli/run-script@^1.8.2": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" - integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== - dependencies: - "@npmcli/node-gyp" "^1.0.2" - "@npmcli/promise-spawn" "^1.3.2" - node-gyp "^7.1.0" - read-package-json-fast "^2.0.1" - -"@nteract/transform-vdom@^4.0.16-alpha.0": - version "4.0.16-alpha.0" - resolved "https://registry.yarnpkg.com/@nteract/transform-vdom/-/transform-vdom-4.0.16-alpha.0.tgz#c0f705cf59b11c14c58ba19ebd6bf8c6f8d99d97" - integrity sha512-eZN/ItKVjXFC3tz67D5r5ORIegOLnIIZKbiyninSGeY3xArEjABU+5iCYjGaqTX1l/lcz2I6ZJ3OQO4KkpsFrg== - dependencies: - lodash.clonedeep "^4.5.0" - -"@octokit/auth-token@^2.4.4": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3" - integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA== - dependencies: - "@octokit/types" "^6.0.3" - -"@octokit/core@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" - integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.0" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - -"@octokit/endpoint@^6.0.1": - version "6.0.12" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" - integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== - dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - -"@octokit/graphql@^4.5.8": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" - integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== - dependencies: - "@octokit/request" "^5.6.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - -"@octokit/openapi-types@^10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-10.0.0.tgz#db4335de99509021f501fc4e026e6ff495fe1e62" - integrity sha512-k1iO2zKuEjjRS1EJb4FwSLk+iF6EGp+ZV0OMRViQoWhQ1fZTk9hg1xccZII5uyYoiqcbC73MRBmT45y1vp2PPg== - -"@octokit/plugin-enterprise-rest@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" - integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== - -"@octokit/plugin-paginate-rest@^2.16.0": - version "2.16.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.0.tgz#09dbda2e5fbca022e3cdf76b63618f7b357c9f0c" - integrity sha512-8YYzALPMvEZ35kgy5pdYvQ22Roz+BIuEaedO575GwE2vb/ACDqQn0xQrTJR4tnZCJn7pi8+AWPVjrFDaERIyXQ== - dependencies: - "@octokit/types" "^6.26.0" - -"@octokit/plugin-request-log@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" - integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== - -"@octokit/plugin-rest-endpoint-methods@^5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.9.0.tgz#f9a7d8411e7e4e49a65fc95b5cc23cf96bf05e1f" - integrity sha512-Rz67pg+rEJq2Qn/qfHsMiBoP7GL5NDn8Gg0ezGznZ745Ixn1gPusZYZqCXNhICYrIZaVXmusNP0iwPdphJneqQ== - dependencies: - "@octokit/types" "^6.26.0" - deprecation "^2.3.1" - -"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" - integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request@^5.6.0": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.1.tgz#f97aff075c37ab1d427c49082fefeef0dba2d8ce" - integrity sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.16.1" - is-plain-object "^5.0.0" - node-fetch "^2.6.1" - universal-user-agent "^6.0.0" - -"@octokit/rest@^18.1.0": - version "18.10.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.10.0.tgz#8a0add9611253e0e31d3ed5b4bc941a3795a7648" - integrity sha512-esHR5OKy38bccL/sajHqZudZCvmv4yjovMJzyXlphaUo7xykmtOdILGJ3aAm0mFHmMLmPFmDMJXf39cAjNJsrw== - dependencies: - "@octokit/core" "^3.5.1" - "@octokit/plugin-paginate-rest" "^2.16.0" - "@octokit/plugin-request-log" "^1.0.4" - "@octokit/plugin-rest-endpoint-methods" "^5.9.0" - -"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.26.0": - version "6.26.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.26.0.tgz#b8af298485d064ad9424cb41520541c1bf820346" - integrity sha512-RDxZBAFMtqs1ZPnbUu1e7ohPNfoNhTiep4fErY7tZs995BeHu369Vsh5woMIaFbllRWEZBfvTCS4hvDnMPiHrA== - dependencies: - "@octokit/openapi-types" "^10.0.0" - -"@phosphor/coreutils@^1.0.0": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@phosphor/coreutils/-/coreutils-1.3.1.tgz#441e34f42340f7faa742a88b2a181947a88d7226" - integrity sha512-9OHCn8LYRcPU/sbHm5v7viCA16Uev3gbdkwqoQqlV+EiauDHl70jmeL7XVDXdigl66Dz0LI11C99XOxp+s3zOA== - -"@playwright/test@^1.16.2": - version "1.22.1" - resolved "https://registry.npmjs.org/@playwright/test/-/test-1.22.1.tgz#78b4a7c13d8a7a0c6432672571d70c4d3963f027" - integrity sha512-8ouMBUboYslHom41W8bnSEn0TwlAMHhCACwOZeuiAgzukj7KobpZ+UBwrGE0jJ0UblJbKAQNRHXL+z7sDSkb6g== - dependencies: - playwright-core "1.22.1" - -"@reach/router@^1.3.3": - version "1.3.4" - resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c" - integrity sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA== - dependencies: - create-react-context "0.3.0" - invariant "^2.2.3" - prop-types "^15.6.1" - react-lifecycles-compat "^3.0.4" - -"@rjsf/core@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@rjsf/core/-/core-3.1.0.tgz#7667364a4532e25c164abbc2adabe39157ffec4c" - integrity sha512-EwM2juiQxEdXzFy9rIIsDr6/e+FYeR1cKx0/no8ASEuXZ1p+/nf/CxKGobzD6UhpRip7JK9PhhuHFEFBIjHFJA== - dependencies: - "@types/json-schema" "^7.0.7" - ajv "^6.7.0" - core-js-pure "^3.6.5" - json-schema-merge-allof "^0.6.0" - jsonpointer "^4.0.1" - lodash "^4.17.15" - nanoid "^3.1.23" - prop-types "^15.7.2" - react-is "^16.9.0" - -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - -"@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" - integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== - dependencies: - "@sinonjs/commons" "^1.7.0" - -"@stdlib/array@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/array/-/array-0.0.12.tgz#12f40ab95bb36d424cdad991f29fc3cb491ee29e" - integrity sha512-nDksiuvRC1dSTHrf5yOGQmlRwAzSKV8MdFQwFSvLbZGGhi5Y4hExqea5HloLgNVouVs8lnAFi2oubSM4Mc7YAg== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/blas" "^0.0.x" - "@stdlib/complex" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/symbol" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/assert@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/assert/-/assert-0.0.12.tgz#1648c9016e5041291f55a6464abcc4069c5103ce" - integrity sha512-38FxFf+ZoQZbdc+m09UsWtaCmzd/2e7im0JOaaFYE7icmRfm+4KiE9BRvBT4tIn7ioLB2f9PsBicKjIsf+tY1w== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/complex" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/fs" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/ndarray" "^0.0.x" - "@stdlib/number" "^0.0.x" - "@stdlib/os" "^0.0.x" - "@stdlib/process" "^0.0.x" - "@stdlib/regexp" "^0.0.x" - "@stdlib/streams" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/symbol" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/bigint@^0.0.x": - version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/bigint/-/bigint-0.0.11.tgz#c416a1d727001c55f4897e6424124199d638f2fd" - integrity sha512-uz0aYDLABAYyqxaCSHYbUt0yPkXYUCR7TrVvHN+UUD3i8FZ02ZKcLO+faKisDyxKEoSFTNtn3Ro8Ir5ebOlVXQ== - dependencies: - "@stdlib/utils" "^0.0.x" - -"@stdlib/blas@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/blas/-/blas-0.0.12.tgz#7e93e42b4621fc6903bf63264f045047333536c2" - integrity sha512-nWY749bWceuoWQ7gz977blCwR7lyQ/rsIXVO4b600h+NFpeA2i/ea7MYC680utIbeu2cnDWHdglBPoK535VAzA== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/number" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/buffer@^0.0.x": - version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/buffer/-/buffer-0.0.11.tgz#6137b00845e6c905181cc7ebfae9f7e47c01b0ce" - integrity sha512-Jeie5eDDa1tVuRcuU+cBXI/oOXSmMxUUccZpqXzgYe0IO8QSNtNxv9mUTzJk/m5wH+lmLoDvNxzPpOH9TODjJg== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/process" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/cli@^0.0.x": - version "0.0.10" - resolved "https://registry.yarnpkg.com/@stdlib/cli/-/cli-0.0.10.tgz#28e2fbe6865d7f5cd15b7dc5846c99bd3b91674f" - integrity sha512-OITGaxG46kwK799+NuOd/+ccosJ9koVuQBC610DDJv0ZJf8mD7sbjGXrmue9C4EOh8MP7Vm/6HN14BojX8oTCg== - dependencies: - "@stdlib/utils" "^0.0.x" - minimist "^1.2.0" - -"@stdlib/complex@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/complex/-/complex-0.0.12.tgz#3afbc190cd0a9b37fc7c6e508c3aa9fda9106944" - integrity sha512-UbZBdaUxT2G+lsTIrVlRZwx2IRY6GXnVILggeejsIVxHSuK+oTyapfetcAv0FJFLP+Rrr+ZzrN4b9G3hBw6NHA== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/constants@^0.0.x": - version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/constants/-/constants-0.0.11.tgz#78cd56d6c2982b30264843c3d75bde7125e90cd2" - integrity sha512-cWKy0L9hXHUQTvFzdPkTvZnn/5Pjv7H4UwY0WC1rLt+A5CxFDJKjvnIi9ypSzJS3CAiGl1ZaHCdadoqXhNdkUg== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/number" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/fs@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/fs/-/fs-0.0.12.tgz#662365fd5846a51f075724b4f2888ae88441b70d" - integrity sha512-zcDLbt39EEM3M3wJW6luChS53B8T+TMJkjs2526UpKJ71O0/0adR57cI7PfCpkMd33d05uM7GM+leEj4eks4Cw== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/process" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/utils" "^0.0.x" - debug "^2.6.9" - -"@stdlib/math@^0.0.x": - version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/math/-/math-0.0.11.tgz#eb6638bc03a20fbd6727dd5b977ee0170bda4649" - integrity sha512-qI78sR1QqGjHj8k/aAqkZ51Su2fyBvaR/jMKQqcB/ML8bpYpf+QGlGvTty5Qdru/wpqds4kVFOVbWGcNFIV2+Q== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/ndarray" "^0.0.x" - "@stdlib/number" "^0.0.x" - "@stdlib/strided" "^0.0.x" - "@stdlib/symbol" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - debug "^2.6.9" - -"@stdlib/ndarray@^0.0.x": - version "0.0.13" - resolved "https://registry.yarnpkg.com/@stdlib/ndarray/-/ndarray-0.0.13.tgz#2e8fc645e10f56a645a0ab81598808c0e8f43b82" - integrity sha512-Z+U9KJP4U2HWrLtuAXSPvhNetAdqaNLMcliR6S/fz+VPlFDeymRK7omRFMgVQ+1zcAvIgKZGJxpLC3vjiPUYEw== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/bigint" "^0.0.x" - "@stdlib/buffer" "^0.0.x" - "@stdlib/complex" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/number" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/nlp@^0.0.x": - version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/nlp/-/nlp-0.0.11.tgz#532ec0f7267b8d639e4c20c6de864e8de8a09054" - integrity sha512-D9avYWANm0Db2W7RpzdSdi5GxRYALGAqUrNnRnnKIO6sMEfr/DvONoAbWruda4QyvSC+0MJNwcEn7+PHhRwYhw== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/random" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/number@^0.0.x": - version "0.0.10" - resolved "https://registry.yarnpkg.com/@stdlib/number/-/number-0.0.10.tgz#4030ad8fc3fac19a9afb415c443cee6deea0e65c" - integrity sha512-RyfoP9MlnX4kccvg8qv7vYQPbLdzfS1Mnp/prGOoWhvMG3pyBwFAan34kwFb5IS/zHC3W5EmrgXCV2QWyLg/Kg== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/os" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/os@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/os/-/os-0.0.12.tgz#08bbf013c62a7153099fa9cbac086ca1349a4677" - integrity sha512-O7lklZ/9XEzoCmYvzjPh7jrFWkbpOSHGI71ve3dkSvBy5tyiSL3TtivfKsIC+9ZxuEJZ3d3lIjc9e+yz4HVbqQ== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/fs" "^0.0.x" - "@stdlib/process" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/process@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/process/-/process-0.0.12.tgz#123325079d89a32f4212f72fb694f8fe3614cf18" - integrity sha512-P0X0TMvkissBE1Wr877Avi2/AxmP7X5Toa6GatHbpJdDg6jQmN4SgPd+NZNp98YtZUyk478c8XSIzMr1krQ20g== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/buffer" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/fs" "^0.0.x" - "@stdlib/streams" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/random@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/random/-/random-0.0.12.tgz#e819c3abd602ed5559ba800dba751e49c633ff85" - integrity sha512-c5yND4Ahnm9Jx0I+jsKhn4Yrz10D53ALSrIe3PG1qIz3kNFcIPnmvCuNGd+3V4ch4Mbrez55Y8z/ZC5RJh4vJQ== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/blas" "^0.0.x" - "@stdlib/buffer" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/fs" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/process" "^0.0.x" - "@stdlib/stats" "^0.0.x" - "@stdlib/streams" "^0.0.x" - "@stdlib/symbol" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - debug "^2.6.9" - readable-stream "^2.1.4" - -"@stdlib/regexp@^0.0.x": - version "0.0.13" - resolved "https://registry.yarnpkg.com/@stdlib/regexp/-/regexp-0.0.13.tgz#80b98361dc7a441b47bc3fa964bb0c826759e971" - integrity sha512-3JT5ZIoq/1nXY+dY+QtkU8/m7oWDeekyItEEXMx9c/AOf0ph8fmvTUGMDNfUq0RetcznFe3b66kFz6Zt4XHviA== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/stats@^0.0.13", "@stdlib/stats@^0.0.x": - version "0.0.13" - resolved "https://registry.yarnpkg.com/@stdlib/stats/-/stats-0.0.13.tgz#87c973f385379d794707c7b5196a173dba8b07e1" - integrity sha512-hm+t32dKbx/L7+7WlQ1o4NDEzV0J4QSnwFBCsIMIAO8+VPxTZ4FxyNERl4oKlS3hZZe4AVKjoOVhBDtgEWrS4g== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/blas" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/ndarray" "^0.0.x" - "@stdlib/random" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/symbol" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/streams@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/streams/-/streams-0.0.12.tgz#07f5ceae5852590afad8e1cb7ce94174becc8739" - integrity sha512-YLUlXwjJNknHp92IkJUdvn5jEQjDckpawKhDLLCoxyh3h5V+w/8+61SH7TMTfKx5lBxKJ8vvtchZh90mIJOAjQ== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/buffer" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/fs" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - debug "^2.6.9" - readable-stream "^2.1.4" - -"@stdlib/strided@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/strided/-/strided-0.0.12.tgz#86ac48e660cb7f64a45cf07e80cbbfe58be21ae1" - integrity sha512-1NINP+Y7IJht34iri/bYLY7TVxrip51f6Z3qWxGHUCH33kvk5H5QqV+RsmFEGbbyoGtdeHrT2O+xA+7R2e3SNg== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/ndarray" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/string@^0.0.x": - version "0.0.13" - resolved "https://registry.yarnpkg.com/@stdlib/string/-/string-0.0.13.tgz#37457ca49e8d1dff0e523c68f5673c655c79eb2d" - integrity sha512-nGMHi7Qk9LBW0+Y+e3pSePQEBqyWH7+7DjFR1APcbsYccJE0p4aCaQdhPhx9Tp7j3uRGBmqPFek8wpcvIuC+CQ== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/fs" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/nlp" "^0.0.x" - "@stdlib/process" "^0.0.x" - "@stdlib/regexp" "^0.0.x" - "@stdlib/streams" "^0.0.x" - "@stdlib/types" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/symbol@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/symbol/-/symbol-0.0.12.tgz#b9f396b0bf269c2985bb7fe99810a8e26d7288c3" - integrity sha512-2IDhpzWVGeLHgsvIsX12RXvf78r7xBkc4QLoRUv3k7Cp61BisR1Ym1p0Tq9PbxT8fknlvLToh9n5RpmESi2d4w== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/time@^0.0.x": - version "0.0.14" - resolved "https://registry.yarnpkg.com/@stdlib/time/-/time-0.0.14.tgz#ea6daa438b1d3b019b99f5091117ee4bcef55d60" - integrity sha512-1gMFCQTabMVIgww+k4g8HHHIhyy1tIlvwT8mC0BHW7Q7TzDAgobwL0bvor+lwvCb5LlDAvNQEpaRgVT99QWGeQ== - dependencies: - "@stdlib/assert" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/fs" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/utils" "^0.0.x" - -"@stdlib/types@^0.0.x": - version "0.0.13" - resolved "https://registry.yarnpkg.com/@stdlib/types/-/types-0.0.13.tgz#4cf4666286294a48c589a37c2b0b48c9076128f9" - integrity sha512-8aPkDtaJM/XZENqhoj7BYuwENLGyxz1xfLIcf2zct7kLZMi0rODzks3n65LEMIR9Rh3rFDXlwc35XvzEkTpmZQ== - -"@stdlib/utils@^0.0.x": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/utils/-/utils-0.0.12.tgz#670de5a7b253f04f11a4cba38f790e82393bcb46" - integrity sha512-+JhFpl6l7RSq/xGnbWRQ5dAL90h9ONj8MViqlb7teBZFtePZLMwoRA1wssypFcJ8SFMRWQn7lPmpYVUkGwRSOg== - dependencies: - "@stdlib/array" "^0.0.x" - "@stdlib/assert" "^0.0.x" - "@stdlib/blas" "^0.0.x" - "@stdlib/buffer" "^0.0.x" - "@stdlib/cli" "^0.0.x" - "@stdlib/constants" "^0.0.x" - "@stdlib/fs" "^0.0.x" - "@stdlib/math" "^0.0.x" - "@stdlib/os" "^0.0.x" - "@stdlib/process" "^0.0.x" - "@stdlib/random" "^0.0.x" - "@stdlib/regexp" "^0.0.x" - "@stdlib/streams" "^0.0.x" - "@stdlib/string" "^0.0.x" - "@stdlib/symbol" "^0.0.x" - "@stdlib/time" "^0.0.x" - "@stdlib/types" "^0.0.x" - debug "^2.6.9" - -"@storybook/addon-actions@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-6.0.20.tgz#4fcf83ec7f961a90a0836633cdf18ecf37d9ed51" - integrity sha512-zO0iol1FQya3cPuVjkq5/YWmmmgXuElIcVQpxndACHGIF6ktwmMJSLToLjfz9Gi5l9LA9/m8j/7FUZrORFtWQQ== - dependencies: - "@storybook/addons" "6.0.20" - "@storybook/api" "6.0.20" - "@storybook/client-api" "6.0.20" - "@storybook/components" "6.0.20" - "@storybook/core-events" "6.0.20" - "@storybook/theming" "6.0.20" - core-js "^3.0.1" - fast-deep-equal "^3.1.1" - global "^4.3.2" - lodash "^4.17.15" - polished "^3.4.4" - prop-types "^15.7.2" - react "^16.8.3" - react-inspector "^5.0.1" - regenerator-runtime "^0.13.3" - ts-dedent "^1.1.1" - util-deprecate "^1.0.2" - uuid "^8.0.0" - -"@storybook/addons@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.0.20.tgz#2c21655db9ffe7606dcabbaf85216f72f4799616" - integrity sha512-UdImOL9+oFgZKjvdpq5Lu9P+UcUm8N6eJzbC8T/eRVomYj1e7sjHs7PyVRsyDiDmhrCKZ5KpNFw3r2yRnav04g== - dependencies: - "@storybook/api" "6.0.20" - "@storybook/channels" "6.0.20" - "@storybook/client-logger" "6.0.20" - "@storybook/core-events" "6.0.20" - "@storybook/router" "6.0.20" - "@storybook/theming" "6.0.20" - core-js "^3.0.1" - global "^4.3.2" - regenerator-runtime "^0.13.3" - -"@storybook/api@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/api/-/api-6.0.20.tgz#93f0175d7aa32765263afe1de8ef099a64d382e6" - integrity sha512-ks68jcQ0AuL8KEkxHJ8byI3P9dySqZjQorqdEPsAfACAUmslKyHVgKUObonm7M5HNOBFItntzp9fow6n9iKzHw== - dependencies: - "@reach/router" "^1.3.3" - "@storybook/channels" "6.0.20" - "@storybook/client-logger" "6.0.20" - "@storybook/core-events" "6.0.20" - "@storybook/csf" "0.0.1" - "@storybook/router" "6.0.20" - "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.0.20" - "@types/reach__router" "^1.3.5" - core-js "^3.0.1" - fast-deep-equal "^3.1.1" - global "^4.3.2" - lodash "^4.17.15" - memoizerific "^1.11.3" - react "^16.8.3" - regenerator-runtime "^0.13.3" - store2 "^2.7.1" - telejson "^5.0.2" - ts-dedent "^1.1.1" - util-deprecate "^1.0.2" - -"@storybook/channel-postmessage@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-6.0.20.tgz#241f295a1ae366cdbe86d0d64b893ffc74117ba9" - integrity sha512-i5bPcrlrtq3s9AYY8w7TP9m8dPMw7jnGqjdD1VuIsrxBG5NAd6BvuPOy022cu7VnGXcVaw56LAMkje+UKWcMEQ== - dependencies: - "@storybook/channels" "6.0.20" - "@storybook/client-logger" "6.0.20" - "@storybook/core-events" "6.0.20" - core-js "^3.0.1" - global "^4.3.2" - qs "^6.6.0" - telejson "^5.0.2" - -"@storybook/channels@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-6.0.20.tgz#cadaf7f47b6ba14497cdd3ac0b0bdc18ba645ffe" - integrity sha512-KH75jHRoK4X/2fzE98X5po7w8X+Us+sy5W+HW31yj8MWh/IgFrOmcXvgWbmGSr1K6uPoAzgNNiCaXvubZ6LIKw== - dependencies: - core-js "^3.0.1" - ts-dedent "^1.1.1" - util-deprecate "^1.0.2" - -"@storybook/client-api@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-6.0.20.tgz#64ae0d06ae66247efb9531b0035d420ed6a939bf" - integrity sha512-uMWltOF5B5BzeeB94U9mADVTie/DgIPdbiDRL6RQF7D9MLl63LoXDrxDZnEB6hzIa/eNQFwXsSVL09fG9Nce5Q== - dependencies: - "@storybook/addons" "6.0.20" - "@storybook/channel-postmessage" "6.0.20" - "@storybook/channels" "6.0.20" - "@storybook/client-logger" "6.0.20" - "@storybook/core-events" "6.0.20" - "@storybook/csf" "0.0.1" - "@types/qs" "^6.9.0" - "@types/webpack-env" "^1.15.2" - core-js "^3.0.1" - global "^4.3.2" - lodash "^4.17.15" - memoizerific "^1.11.3" - qs "^6.6.0" - stable "^0.1.8" - store2 "^2.7.1" - ts-dedent "^1.1.1" - util-deprecate "^1.0.2" - -"@storybook/client-logger@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-6.0.20.tgz#552a0aa39e437dd4c0d04f1db60e76dbff6e3dcc" - integrity sha512-JRYKAMIy6Mdbrjrt+U04gRv3auPO3QKqCcXJxNmbEuuJZExVYZ8kvL1ic9OzV/go+7GZ5ok1y5FODxvfCKbxXg== - dependencies: - core-js "^3.0.1" - global "^4.3.2" - -"@storybook/components@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-6.0.20.tgz#0504da6284825a8379247b5cb8a30ee81ea72c06" - integrity sha512-figLDrtGHB90V1bi/oQ7E7vmma0A4F4thgohrxFzjoQOf3yfm8vvWbQdOYsBkH0je+NmjxyPDGN62QAWhqfLLg== - dependencies: - "@storybook/client-logger" "6.0.20" - "@storybook/csf" "0.0.1" - "@storybook/theming" "6.0.20" - "@types/overlayscrollbars" "^1.9.0" - "@types/react-color" "^3.0.1" - "@types/react-syntax-highlighter" "11.0.4" - core-js "^3.0.1" - fast-deep-equal "^3.1.1" - global "^4.3.2" - lodash "^4.17.15" - markdown-to-jsx "^6.11.4" - memoizerific "^1.11.3" - overlayscrollbars "^1.10.2" - polished "^3.4.4" - popper.js "^1.14.7" - react "^16.8.3" - react-color "^2.17.0" - react-dom "^16.8.3" - react-popper-tooltip "^2.11.0" - react-syntax-highlighter "^12.2.1" - react-textarea-autosize "^8.1.1" - ts-dedent "^1.1.1" - -"@storybook/core-events@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-6.0.20.tgz#cf86fc4315e9ba064a08a0e313e419375ab07abd" - integrity sha512-0UIgBRx5n7CaBAb1JQBSUm0+MI7+7hnJSM6bjwcvBSZxpqSY9txPlQyxmzt5xTDJQye1HxmL1IpHfMxvzATLuQ== - dependencies: - core-js "^3.0.1" - -"@storybook/core@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/core/-/core-6.0.20.tgz#8ba3d9e128287e004654b8480b650e8f3ccddc8a" - integrity sha512-FvoHQ03YvTXVaGPqsZ98CBESZGQ69cZh+0K4kbOEfSY76xXpCbY9kIQ6ynHHQEPJdC2kFX97YRsOuSTY1AZqVQ== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.8.3" - "@babel/plugin-proposal-decorators" "^7.8.3" - "@babel/plugin-proposal-export-default-from" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.1" - "@babel/plugin-proposal-object-rest-spread" "^7.9.6" - "@babel/plugin-proposal-optional-chaining" "^7.10.1" - "@babel/plugin-proposal-private-methods" "^7.8.3" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.8.3" - "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.9.5" - "@babel/plugin-transform-destructuring" "^7.9.5" - "@babel/plugin-transform-for-of" "^7.9.0" - "@babel/plugin-transform-parameters" "^7.9.5" - "@babel/plugin-transform-shorthand-properties" "^7.8.3" - "@babel/plugin-transform-spread" "^7.8.3" - "@babel/plugin-transform-template-literals" "^7.8.3" - "@babel/preset-env" "^7.9.6" - "@babel/preset-react" "^7.8.3" - "@babel/preset-typescript" "^7.9.0" - "@babel/register" "^7.10.5" - "@storybook/addons" "6.0.20" - "@storybook/api" "6.0.20" - "@storybook/channel-postmessage" "6.0.20" - "@storybook/channels" "6.0.20" - "@storybook/client-api" "6.0.20" - "@storybook/client-logger" "6.0.20" - "@storybook/components" "6.0.20" - "@storybook/core-events" "6.0.20" - "@storybook/csf" "0.0.1" - "@storybook/node-logger" "6.0.20" - "@storybook/router" "6.0.20" - "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.0.20" - "@storybook/ui" "6.0.20" - "@types/glob-base" "^0.3.0" - "@types/micromatch" "^4.0.1" - "@types/node-fetch" "^2.5.4" - airbnb-js-shims "^2.2.1" - ansi-to-html "^0.6.11" - autoprefixer "^9.7.2" - babel-loader "^8.0.6" - babel-plugin-emotion "^10.0.20" - babel-plugin-macros "^2.8.0" - babel-preset-minify "^0.5.0 || 0.6.0-alpha.5" - better-opn "^2.0.0" - boxen "^4.1.0" - case-sensitive-paths-webpack-plugin "^2.2.0" - chalk "^4.0.0" - cli-table3 "0.6.0" - commander "^5.0.0" - core-js "^3.0.1" - css-loader "^3.5.3" - detect-port "^1.3.0" - dotenv-webpack "^1.7.0" - ejs "^3.1.2" - express "^4.17.0" - file-loader "^6.0.0" - file-system-cache "^1.0.5" - find-up "^4.1.0" - fork-ts-checker-webpack-plugin "^4.1.4" - fs-extra "^9.0.0" - glob "^7.1.6" - glob-base "^0.3.0" - glob-promise "^3.4.0" - global "^4.3.2" - html-webpack-plugin "^4.2.1" - inquirer "^7.0.0" - interpret "^2.0.0" - ip "^1.1.5" - json5 "^2.1.1" - lazy-universal-dotenv "^3.0.1" - micromatch "^4.0.2" - node-fetch "^2.6.0" - pkg-dir "^4.2.0" - pnp-webpack-plugin "1.6.4" - postcss-flexbugs-fixes "^4.1.0" - postcss-loader "^3.0.0" - pretty-hrtime "^1.0.3" - qs "^6.6.0" - raw-loader "^4.0.1" - react-dev-utils "^10.0.0" - regenerator-runtime "^0.13.3" - resolve-from "^5.0.0" - serve-favicon "^2.5.0" - shelljs "^0.8.3" - stable "^0.1.8" - style-loader "^1.2.1" - terser-webpack-plugin "^3.0.0" - ts-dedent "^1.1.1" - unfetch "^4.1.0" - url-loader "^4.0.0" - util-deprecate "^1.0.2" - webpack "^4.43.0" - webpack-dev-middleware "^3.7.0" - webpack-hot-middleware "^2.25.0" - webpack-virtual-modules "^0.2.2" - -"@storybook/csf@0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.0.1.tgz#95901507dc02f0bc6f9ac8ee1983e2fc5bb98ce6" - integrity sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw== - dependencies: - lodash "^4.17.15" - -"@storybook/node-logger@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-6.0.20.tgz#d90c10a4d848b4395be0e16f1ad38f37eba7a792" - integrity sha512-7dQZgjk496/iTlmEoRMreIDG0iqu5WClL2LPvUeRC484H/IIpKCMmuAHSPkhnp/kj59fWZES6ruuKZr5c9f04A== - dependencies: - "@types/npmlog" "^4.1.2" - chalk "^4.0.0" - core-js "^3.0.1" - npmlog "^4.1.2" - pretty-hrtime "^1.0.3" - -"@storybook/react@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-6.0.20.tgz#bf5ab1f291918ad74f1f7777af494b85eec993dd" - integrity sha512-+OQwsCY0IFG2HnirwcoSACJiLQK4F0iJxaJO1xzXkouYHNOLeCpRt9fjn8OdhPNyDZSr0SvU7U9k5p1U+6N0Og== - dependencies: - "@babel/preset-flow" "^7.0.0" - "@babel/preset-react" "^7.0.0" - "@storybook/addons" "6.0.20" - "@storybook/core" "6.0.20" - "@storybook/node-logger" "6.0.20" - "@storybook/semver" "^7.3.2" - "@svgr/webpack" "^5.4.0" - "@types/webpack-env" "^1.15.2" - babel-plugin-add-react-displayname "^0.0.5" - babel-plugin-named-asset-import "^0.3.1" - babel-plugin-react-docgen "^4.1.0" - core-js "^3.0.1" - global "^4.3.2" - lodash "^4.17.15" - prop-types "^15.7.2" - react-dev-utils "^10.0.0" - react-docgen-typescript-plugin "^0.5.2" - regenerator-runtime "^0.13.3" - ts-dedent "^1.1.1" - webpack "^4.43.0" - -"@storybook/router@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/router/-/router-6.0.20.tgz#f81ce852b5173e5c2afeead19af0d66326fe7ebc" - integrity sha512-mHd/ZGc0rGenozrITmzkMKVSTdGztBqEQXPLMGaL2f7+kQENHcbMe0KL90Hh54WnUUfupO2pQf76Pvw7JPN5NQ== - dependencies: - "@reach/router" "^1.3.3" - "@types/reach__router" "^1.3.5" - core-js "^3.0.1" - global "^4.3.2" - memoizerific "^1.11.3" - qs "^6.6.0" - -"@storybook/semver@^7.3.2": - version "7.3.2" - resolved "https://registry.yarnpkg.com/@storybook/semver/-/semver-7.3.2.tgz#f3b9c44a1c9a0b933c04e66d0048fcf2fa10dac0" - integrity sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg== - dependencies: - core-js "^3.6.5" - find-up "^4.1.0" - -"@storybook/theming@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.0.20.tgz#a7d4b953552dc9cc7431497ec7920774d21ae24f" - integrity sha512-gTDq3Qu/LuJ04/4quld0/oFnW2gIaKEYxwIyAoIjZ3wKOsGyleBEFPZEtyQaKZkzQMh4mkmO020ckDz9+XH0jg== - dependencies: - "@emotion/core" "^10.0.20" - "@emotion/is-prop-valid" "^0.8.6" - "@emotion/styled" "^10.0.17" - "@storybook/client-logger" "6.0.20" - core-js "^3.0.1" - deep-object-diff "^1.1.0" - emotion-theming "^10.0.19" - global "^4.3.2" - memoizerific "^1.11.3" - polished "^3.4.4" - resolve-from "^5.0.0" - ts-dedent "^1.1.1" - -"@storybook/ui@6.0.20": - version "6.0.20" - resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-6.0.20.tgz#8e7f8d63c88714056993a484185a856b788fc3eb" - integrity sha512-VdOqMZDH0u4FxEnv0RLjezvKW7bRSzSiJwW0MUnp/8YTLXnRSr0l2O8uYEGVg24fY4tUMMM1kkUrtLYEA73sUQ== - dependencies: - "@emotion/core" "^10.0.20" - "@storybook/addons" "6.0.20" - "@storybook/api" "6.0.20" - "@storybook/channels" "6.0.20" - "@storybook/client-logger" "6.0.20" - "@storybook/components" "6.0.20" - "@storybook/core-events" "6.0.20" - "@storybook/router" "6.0.20" - "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.0.20" - "@types/markdown-to-jsx" "^6.11.0" - copy-to-clipboard "^3.0.8" - core-js "^3.0.1" - core-js-pure "^3.0.1" - emotion-theming "^10.0.19" - fuse.js "^3.6.1" - global "^4.3.2" - lodash "^4.17.15" - markdown-to-jsx "^6.11.4" - memoizerific "^1.11.3" - polished "^3.4.4" - qs "^6.6.0" - react "^16.8.3" - react-dom "^16.8.3" - react-draggable "^4.0.3" - react-helmet-async "^1.0.2" - react-hotkeys "2.0.0" - react-sizeme "^2.6.7" - regenerator-runtime "^0.13.3" - resolve-from "^5.0.0" - store2 "^2.7.1" - -"@svgr/babel-plugin-add-jsx-attribute@^5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906" - integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg== - -"@svgr/babel-plugin-remove-jsx-attribute@^5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef" - integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg== - -"@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd" - integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA== - -"@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897" - integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ== - -"@svgr/babel-plugin-svg-dynamic-title@^5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7" - integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg== - -"@svgr/babel-plugin-svg-em-dimensions@^5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0" - integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw== - -"@svgr/babel-plugin-transform-react-native-svg@^5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80" - integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q== - -"@svgr/babel-plugin-transform-svg-component@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz#583a5e2a193e214da2f3afeb0b9e8d3250126b4a" - integrity sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ== - -"@svgr/babel-preset@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-5.5.0.tgz#8af54f3e0a8add7b1e2b0fcd5a882c55393df327" - integrity sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig== - dependencies: - "@svgr/babel-plugin-add-jsx-attribute" "^5.4.0" - "@svgr/babel-plugin-remove-jsx-attribute" "^5.4.0" - "@svgr/babel-plugin-remove-jsx-empty-expression" "^5.0.1" - "@svgr/babel-plugin-replace-jsx-attribute-value" "^5.0.1" - "@svgr/babel-plugin-svg-dynamic-title" "^5.4.0" - "@svgr/babel-plugin-svg-em-dimensions" "^5.4.0" - "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0" - "@svgr/babel-plugin-transform-svg-component" "^5.5.0" - -"@svgr/core@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@svgr/core/-/core-5.5.0.tgz#82e826b8715d71083120fe8f2492ec7d7874a579" - integrity sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ== - dependencies: - "@svgr/plugin-jsx" "^5.5.0" - camelcase "^6.2.0" - cosmiconfig "^7.0.0" - -"@svgr/hast-util-to-babel-ast@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz#5ee52a9c2533f73e63f8f22b779f93cd432a5461" - integrity sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ== - dependencies: - "@babel/types" "^7.12.6" - -"@svgr/plugin-jsx@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz#1aa8cd798a1db7173ac043466d7b52236b369000" - integrity sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA== - dependencies: - "@babel/core" "^7.12.3" - "@svgr/babel-preset" "^5.5.0" - "@svgr/hast-util-to-babel-ast" "^5.5.0" - svg-parser "^2.0.2" - -"@svgr/plugin-svgo@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz#02da55d85320549324e201c7b2e53bf431fcc246" - integrity sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ== - dependencies: - cosmiconfig "^7.0.0" - deepmerge "^4.2.2" - svgo "^1.2.2" - -"@svgr/webpack@^5.4.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-5.5.0.tgz#aae858ee579f5fa8ce6c3166ef56c6a1b381b640" - integrity sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g== - dependencies: - "@babel/core" "^7.12.3" - "@babel/plugin-transform-react-constant-elements" "^7.12.1" - "@babel/preset-env" "^7.12.1" - "@babel/preset-react" "^7.12.5" - "@svgr/core" "^5.5.0" - "@svgr/plugin-jsx" "^5.5.0" - "@svgr/plugin-svgo" "^5.5.0" - loader-utils "^2.0.0" - -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": - version "7.1.15" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.15.tgz#2ccfb1ad55a02c83f8e0ad327cbc332f55eb1024" - integrity sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" - integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" - integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== - dependencies: - "@babel/types" "^7.3.0" - -"@types/base16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/base16/-/base16-1.0.2.tgz#eb3a07db52309bfefb9ba010dfdb3c0784971f65" - integrity sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg== - -"@types/braces@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/braces/-/braces-3.0.1.tgz#5a284d193cfc61abb2e5a50d36ebbc50d942a32b" - integrity sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ== - -"@types/clone@~2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/clone/-/clone-2.1.1.tgz#9b880d0ce9b1f209b5e0bd6d9caa38209db34024" - integrity sha512-BZIU34bSYye0j/BFcPraiDZ5ka6MJADjcDVELGf7glr9K+iE8NYVjFslJFVWzskSxkLLyCrSPScE82/UUoBSvg== - -"@types/codemirror@^0.0.109": - version "0.0.109" - resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.109.tgz#89d575ff1c7b462c4c3b8654f8bb38e5622e9036" - integrity sha512-cSdiHeeLjvGn649lRTNeYrVCDOgDrtP+bDDSFDd1TF+i0jKGPDRozno2NOJ9lTniso+taiv4kiVS8dgM8Jm5lg== - dependencies: - "@types/tern" "*" - -"@types/dom4@^2.0.1": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.2.tgz#6495303f049689ce936ed328a3e5ede9c51408ee" - integrity sha512-Rt4IC1T7xkCWa0OG1oSsPa0iqnxlDeQqKXZAHrQGLb7wFGncWm85MaxKUjAGejOrUynOgWlFi4c6S6IyJwoK4g== - -"@types/eslint-scope@^3.7.0": - version "3.7.1" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e" - integrity sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "7.2.14" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.14.tgz#088661518db0c3c23089ab45900b99dd9214b92a" - integrity sha512-pESyhSbUOskqrGcaN+bCXIQDyT5zTaRWfj5ZjjSlMatgGjIn3QQPfocAu4WSabUR7CGyLZ2CQaZyISOEX7/saw== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@^0.0.50": - version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" - integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== - -"@types/fs-extra@^9.0.1": - version "9.0.12" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.12.tgz#9b8f27973df8a7a3920e8461517ebf8a7d4fdfaf" - integrity sha512-I+bsBr67CurCGnSenZZ7v94gd3tc3+Aj2taxMT4yu4ABLuOgOjeFxX3dokG24ztSRg5tnT00sL8BszO7gSMoIw== - dependencies: - "@types/node" "*" - -"@types/glob-base@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@types/glob-base/-/glob-base-0.3.0.tgz#a581d688347e10e50dd7c17d6f2880a10354319d" - integrity sha1-pYHWiDR+EOUN18F9byiAoQNUMZ0= - -"@types/glob@*", "@types/glob@^7.1.1": - version "7.1.4" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" - integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - -"@types/graceful-fs@^4.1.2": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" - integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== - dependencies: - "@types/node" "*" - -"@types/html-minifier-terser@^5.0.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" - integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w== - -"@types/inquirer@^7.3.1": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.3.tgz#92e6676efb67fa6925c69a2ee638f67a822952ac" - integrity sha512-HhxyLejTHMfohAuhRun4csWigAMjXTmRyiJTU1Y/I1xmggikFMkOUoMQRlFm+zQcPEGHSs3io/0FAmNZf8EymQ== - dependencies: - "@types/through" "*" - rxjs "^6.4.0" - -"@types/is-function@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.0.tgz#1b0b819b1636c7baf0d6785d030d12edf70c3e83" - integrity sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w== - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" - integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@^26.0.10": - version "26.0.24" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" - integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== - dependencies: - jest-diff "^26.0.0" - pretty-format "^26.0.0" - -"@types/json-schema@*", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7": - version "7.0.8" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818" - integrity sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg== - -"@types/json5@^0.0.30": - version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818" - integrity sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA== - -"@types/lodash.curry@^4.1.6": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/lodash.curry/-/lodash.curry-4.1.6.tgz#f26c490c80c92d7cbaa2300d542e89781d44b1ff" - integrity sha512-x3ctCcmOYqRrihNNnQJW6fe/yZFCgnrIa6p80AiPQRO8Jis29bBdy1dEw1FwngoF/mCZa3Bx+33fUZvOEE635Q== - dependencies: - "@types/lodash" "*" - -"@types/lodash.escape@^4.0.6": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@types/lodash.escape/-/lodash.escape-4.0.6.tgz#71730c1a27bb5ac7f98f88d5e858fa4ad2df1106" - integrity sha512-/CI97B3wf1R4oD4yotsGoX/5bobL/RC8olTQ16iunzdjufcdD8GyIvNDatg1IfzVKaFBZmxuY0+WQDpdaQHLzg== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.14.171" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.171.tgz#f01b3a5fe3499e34b622c362a46a609fdb23573b" - integrity sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg== - -"@types/lodash@^4.14.175": - version "4.14.191" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa" - integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ== - -"@types/markdown-to-jsx@^6.11.0": - version "6.11.3" - resolved "https://registry.yarnpkg.com/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz#cdd1619308fecbc8be7e6a26f3751260249b020e" - integrity sha512-30nFYpceM/ZEvhGiqWjm5quLUxNeld0HCzJEXMZZDpq53FPkS85mTwkWtCXzCqq8s5JYLgM5W392a02xn8Bdaw== - dependencies: - "@types/react" "*" - -"@types/marked@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.3.tgz#2098f4a77adaba9ce881c9e0b6baf29116e5acc4" - integrity sha512-HnMWQkLJEf/PnxZIfbm0yGJRRZYYMhb++O9M36UCTA9z53uPvVoSlAwJr3XOpDEryb7Hwl1qAx/MV6YIW1RXxg== - -"@types/micromatch@^4.0.1": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/micromatch/-/micromatch-4.0.2.tgz#ce29c8b166a73bf980a5727b1e4a4d099965151d" - integrity sha512-oqXqVb0ci19GtH0vOA/U2TmHTcRY9kuZl4mqUxe0QmJAlIW13kzhuK5pi1i9+ngav8FjpSb9FVS/GE00GLX1VA== - dependencies: - "@types/braces" "*" - -"@types/minimatch@*", "@types/minimatch@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== - -"@types/minimist@^1.2.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== - -"@types/node-fetch@^2.5.4": - version "2.5.11" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.11.tgz#ce22a2e65fc8999f4dbdb7ddbbcf187d755169e4" - integrity sha512-2upCKaqVZETDRb8A2VTaRymqFBEgH8u6yr96b/u3+1uQEPDRo3mJLEiPk7vdXBHRtjwkjqzFYMJXrt0Z9QsYjQ== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - -"@types/node@*", "@types/node@^14.6.1": - version "14.17.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.11.tgz#82d266d657aec5ff01ca59f2ffaff1bb43f7bf0f" - integrity sha512-n2OQ+0Bz6WEsUjrvcHD1xZ8K+Kgo4cn9/w94s1bJS690QMUWfJPW/m7CCb7gPkA1fcYwL2UpjXP/rq/Eo41m6w== - -"@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== - -"@types/npmlog@^4.1.2": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@types/npmlog/-/npmlog-4.1.3.tgz#9c24b49a97e25cf15a890ff404764080d7942132" - integrity sha512-1TcL7YDYCtnHmLhTWbum+IIwLlvpaHoEKS2KNIngEwLzwgDeHaebaEHHbQp8IqzNQ9IYiboLKUjAf7MZqG63+w== - -"@types/overlayscrollbars@^1.9.0": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@types/overlayscrollbars/-/overlayscrollbars-1.12.1.tgz#fb637071b545834fb12aea94ee309a2ff4cdc0a8" - integrity sha512-V25YHbSoKQN35UasHf0EKD9U2vcmexRSp78qa8UglxFH8H3D+adEa9zGZwrqpH4TdvqeMrgMqVqsLB4woAryrQ== - -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - -"@types/prettier@^2.0.0", "@types/prettier@~2.1.0": - version "2.1.6" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.6.tgz#f4b1efa784e8db479cdb8b14403e2144b1e9ff03" - integrity sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA== - -"@types/prop-types@*", "@types/prop-types@^15.7.3": - version "15.7.4" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" - integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== - -"@types/q@^1.5.1": - version "1.5.5" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" - integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== - -"@types/qs@^6.9.0": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/reach__router@^1.3.5": - version "1.3.9" - resolved "https://registry.yarnpkg.com/@types/reach__router/-/reach__router-1.3.9.tgz#d3aaac0072665c81063cc6c557c18dadd642b226" - integrity sha512-N6rqQqTTAV/zKLfK3iq9Ww3wqCEhTZvsilhl0zI09zETdVq1QGmJH6+/xnj8AFUWIrle2Cqo+PGM/Ltr1vBb9w== - dependencies: - "@types/react" "*" - -"@types/react-color@^3.0.1": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.5.tgz#b8bdf8df7085bd1577658fb37d9a18d7ba3963bb" - integrity sha512-0VZy8Uq5x04cW5QFz24Qw8MMMlsMi8Bb+XG5h59ATqPnWVq6OheHtrwv5LeakdTRDaECQnExJNSFOsSe4Eo/zQ== - dependencies: - "@types/react" "*" - "@types/reactcss" "*" - -"@types/react-dom@^17.0.0": - version "17.0.9" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.9.tgz#441a981da9d7be117042e1a6fd3dac4b30f55add" - integrity sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg== - dependencies: - "@types/react" "*" - -"@types/react-highlighter@^0.3.4": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@types/react-highlighter/-/react-highlighter-0.3.4.tgz#18cf2b1516164c8a7a697aa3f7d237df6c2b5a34" - integrity sha512-wM8l3QxU1P6rAeCIJUNug407Z8igm90xX9jDpjem1+pVzEI3VQpKiQj7oEinQVq7425Dmgyon8XfqbxD0mTknA== - dependencies: - "@types/react" "*" - -"@types/react-json-tree@^0.6.11": - version "0.6.11" - resolved "https://registry.yarnpkg.com/@types/react-json-tree/-/react-json-tree-0.6.11.tgz#644eee18b1c772d57afe584b8098af71d847a15a" - integrity sha512-HP0Sf0ZHjCi1FHLJxh/pLaxaevEW6ILlV2C5Dn3EZFTkLjWkv+EVf/l/zvtmoU9ZwuO/3TKVeWK/700UDxunTw== - dependencies: - "@types/react" "*" - -"@types/react-paginate@^6.2.1": - version "6.2.3" - resolved "https://registry.yarnpkg.com/@types/react-paginate/-/react-paginate-6.2.3.tgz#931ee688bafa2477d146f0f9bb778cd188855e4e" - integrity sha512-msO6YaYrGlPLxLyJ3kSoXVXcTrMcAVuBTS2ksJ1jG72w9loN9EHZXu6G+cPUYOZSuuvt+EUQC3t0B+fjldC1Tg== - dependencies: - "@types/react" "*" - -"@types/react-syntax-highlighter@11.0.4": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz#d86d17697db62f98046874f62fdb3e53a0bbc4cd" - integrity sha512-9GfTo3a0PHwQeTVoqs0g5bS28KkSY48pp5659wA+Dp4MqceDEa8EHBqrllJvvtyusszyJhViUEap0FDvlk/9Zg== - dependencies: - "@types/react" "*" - -"@types/react@*", "@types/react@^17.0.0": - version "17.0.14" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.14.tgz#f0629761ca02945c4e8fea99b8177f4c5c61fb0f" - integrity sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/reactcss@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/reactcss/-/reactcss-1.2.4.tgz#66c5f6afe123ffa1a50dbe724aa1fe68eb9fab00" - integrity sha512-1rhVqteMSD6KQjO+dPBObE1OkKadw00HVJkG5WCYsyvMwGgdTZ530wF7Bkrg/4TWxB2AtINIzFotjW51eViw+w== - dependencies: - "@types/react" "*" - -"@types/resize-observer-browser@^0.1.7": - version "0.1.7" - resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.7.tgz#294aaadf24ac6580b8fbd1fe3ab7b59fe85f9ef3" - integrity sha512-G9eN0Sn0ii9PWQ3Vl72jDPgeJwRWhv2Qk/nQkJuWmRmOB4HX3/BhD5SE1dZs/hzPZL/WKnvF0RHdTSG54QJFyg== - -"@types/sanitize-html@^2.3.1": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/sanitize-html/-/sanitize-html-2.3.2.tgz#ed234985fd8a07af8dd7ced488021f44ccfa2e91" - integrity sha512-DnmoXsiqG2/RoSf6/lD3Hrs+TCM8ILtzNuuSjmOtRaP/ud9Sy3M3ctwD+SB50EIDs5GzVFF1dJk2Fq/ID/PNCQ== - dependencies: - htmlparser2 "^6.0.0" - -"@types/scheduler@*": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== - -"@types/semver@^7.3.3": - version "7.3.7" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.7.tgz#b9eb89d7dfa70d5d1ce525bc1411a35347f533a3" - integrity sha512-4g1jrL98mdOIwSOUh6LTlB0Cs9I0dQPwINUhBg7C6pN4HLr8GS8xsksJxilW6S6dQHVi2K/o+lQuQcg7LroCnw== - -"@types/source-list-map@*": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" - integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== - -"@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - -"@types/supports-color@^5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@types/supports-color/-/supports-color-5.3.0.tgz#eb6a52e9531fb3ebcd401cec774d1bdfb571f793" - integrity sha512-WxwTXnHTIsk7srax1icjLgX+6w1MUAJbhyCpRP/45paEElsPDQUJZDgr1UpKuL2S3Tb+ZyX9MjWwmcSD4bUoOQ== - -"@types/tapable@^1", "@types/tapable@^1.0.5": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.8.tgz#b94a4391c85666c7b73299fd3ad79d4faa435310" - integrity sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ== - -"@types/tern@*": - version "0.23.4" - resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" - integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== - dependencies: - "@types/estree" "*" - -"@types/text-encoding@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@types/text-encoding/-/text-encoding-0.0.35.tgz#6f14474e0b232bc70c59677aadc65dcc5a99c3a9" - integrity sha512-jfo/A88XIiAweUa8np+1mPbm3h2w0s425YrI8t3wk5QxhH6UI7w517MboNVnGDeMSuoFwA8Rwmklno+FicvV4g== - -"@types/through@*": - version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895" - integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg== - dependencies: - "@types/node" "*" - -"@types/uglify-js@*": - version "3.13.1" - resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.1.tgz#5e889e9e81e94245c75b6450600e1c5ea2878aea" - integrity sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ== - dependencies: - source-map "^0.6.1" - -"@types/url-parse@^1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@types/url-parse/-/url-parse-1.4.3.tgz#fba49d90f834951cb000a674efee3d6f20968329" - integrity sha512-4kHAkbV/OfW2kb5BLVUuUMoumB3CP8rHqlw48aHvFy5tf9ER0AfOonBlX29l/DD68G70DmyhRlSYfQPSYpC5Vw== - -"@types/webpack-env@^1.14.1", "@types/webpack-env@^1.15.2": - version "1.16.2" - resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.2.tgz#8db514b059c1b2ae14ce9d7bb325296de6a9a0fa" - integrity sha512-vKx7WNQNZDyJveYcHAm9ZxhqSGLYwoyLhrHjLBOkw3a7cT76sTdjgtwyijhk1MaHyRIuSztcVwrUOO/NEu68Dw== - -"@types/webpack-sources@*", "@types/webpack-sources@^0.1.5": - version "0.1.9" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.9.tgz#da69b06eb34f6432e6658acb5a6893c55d983920" - integrity sha512-bvzMnzqoK16PQIC8AYHNdW45eREJQMd6WG/msQWX5V2+vZmODCOPb4TJcbgRljTZZTwTM4wUMcsI8FftNA7new== - dependencies: - "@types/node" "*" - "@types/source-list-map" "*" - source-map "^0.6.1" - -"@types/webpack@^4.41.8": - version "4.41.30" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.30.tgz#fd3db6d0d41e145a8eeeafcd3c4a7ccde9068ddc" - integrity sha512-GUHyY+pfuQ6haAfzu4S14F+R5iGRwN6b2FRNJY7U0NilmFAqbsOfK6j1HwuLBAqwRIT+pVdNDJGJ6e8rpp0KHA== - dependencies: - "@types/node" "*" - "@types/tapable" "^1" - "@types/uglify-js" "*" - "@types/webpack-sources" "*" - anymatch "^3.0.0" - source-map "^0.6.0" - -"@types/ws@^7.4.4": - version "7.4.6" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.6.tgz#c4320845e43d45a7129bb32905e28781c71c1fff" - integrity sha512-ijZ1vzRawI7QoWnTNL8KpHixd2b2XVb9I9HAqI3triPsh1EC0xH0Eg6w2O3TKbDCgiNNlJqfrof6j4T2I+l9vw== - dependencies: - "@types/node" "*" - -"@types/yargs-parser@*": - version "20.2.1" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" - integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== - -"@types/yargs@^15.0.0": - version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" - integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@~4.8.1": - version "4.8.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.8.2.tgz#cf9102ec800391caa574f589ffe0623cca1d9308" - integrity sha512-gQ06QLV5l1DtvYtqOyFLXD9PdcILYqlrJj2l+CGDlPtmgLUzc1GpqciJFIRvyfvgLALpnxYINFuw+n9AZhPBKQ== - dependencies: - "@typescript-eslint/experimental-utils" "4.8.2" - "@typescript-eslint/scope-manager" "4.8.2" - debug "^4.1.1" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@4.8.2", "@typescript-eslint/experimental-utils@^4.0.1": - version "4.8.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.8.2.tgz#8909a5732f19329cf5ef0c39766170476bff5e50" - integrity sha512-hpTw6o6IhBZEsQsjuw/4RWmceRyESfAiEzAEnXHKG1X7S5DXFaZ4IO1JO7CW1aQ604leQBzjZmuMI9QBCAJX8Q== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.8.2" - "@typescript-eslint/types" "4.8.2" - "@typescript-eslint/typescript-estree" "4.8.2" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@~4.8.1": - version "4.8.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.8.2.tgz#78dccbe5124de2b8dea2d4c363dee9f769151ca8" - integrity sha512-u0leyJqmclYr3KcXOqd2fmx6SDGBO0MUNHHAjr0JS4Crbb3C3d8dwAdlazy133PLCcPn+aOUFiHn72wcuc5wYw== - dependencies: - "@typescript-eslint/scope-manager" "4.8.2" - "@typescript-eslint/types" "4.8.2" - "@typescript-eslint/typescript-estree" "4.8.2" - debug "^4.1.1" - -"@typescript-eslint/scope-manager@4.8.2": - version "4.8.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz#a18388c63ae9c17adde519384f539392f2c4f0d9" - integrity sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g== - dependencies: - "@typescript-eslint/types" "4.8.2" - "@typescript-eslint/visitor-keys" "4.8.2" - -"@typescript-eslint/types@4.8.2": - version "4.8.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.8.2.tgz#c862dd0e569d9478eb82d6aee662ea53f5661a36" - integrity sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw== - -"@typescript-eslint/typescript-estree@4.8.2": - version "4.8.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz#eeec34707d8577600fb21661b5287226cc8b3bed" - integrity sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg== - dependencies: - "@typescript-eslint/types" "4.8.2" - "@typescript-eslint/visitor-keys" "4.8.2" - debug "^4.1.1" - globby "^11.0.1" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/visitor-keys@4.8.2": - version "4.8.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz#62cd3fbbbf65f8eccfbe6f159eb1b84a243a3f77" - integrity sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw== - dependencies: - "@typescript-eslint/types" "4.8.2" - eslint-visitor-keys "^2.0.0" - -"@verdaccio/commons-api@10.2.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/@verdaccio/commons-api/-/commons-api-10.2.0.tgz#3b684c31749837b0574375bb2e10644ecea9fcca" - integrity sha512-F/YZANu4DmpcEV0jronzI7v2fGVWkQ5Mwi+bVmV+ACJ+EzR0c9Jbhtbe5QyLUuzR97t8R5E/Xe53O0cc2LukdQ== - dependencies: - http-errors "2.0.0" - http-status-codes "2.2.0" - -"@verdaccio/config@6.0.0-6-next.60": - version "6.0.0-6-next.60" - resolved "https://registry.yarnpkg.com/@verdaccio/config/-/config-6.0.0-6-next.60.tgz#cd290e36ff07aefd698e637aeac9645444486c9b" - integrity sha512-q6r8JEXUV2piZUtWW5SR11vIVqO4b4OGKmAnwCf6EdszRoRcxzf9KBlktVxSzmoIUOvygf0a+3hGbGI9qZBSjw== - dependencies: - "@verdaccio/core" "6.0.0-6-next.60" - "@verdaccio/utils" "6.0.0-6-next.28" - debug "4.3.4" - lodash "4.17.21" - minimatch "3.1.2" - yaml "2.2.0" - yup "0.32.11" - -"@verdaccio/config@6.0.0-6-next.61": - version "6.0.0-6-next.61" - resolved "https://registry.yarnpkg.com/@verdaccio/config/-/config-6.0.0-6-next.61.tgz#04116ec345a7a5645a3f2618b7d15c5a8e71c4bf" - integrity sha512-gvR6vRS5aXTwEhZSecqEEOlTGHqbV2Vjg7w/huGRuAuJlOuz2t4V3d499U4qkkLBBEhh/X+4DjEVrkOo+jVWzQ== - dependencies: - "@verdaccio/core" "6.0.0-6-next.61" - "@verdaccio/utils" "6.0.0-6-next.29" - debug "4.3.4" - js-yaml "4.1.0" - lodash "4.17.21" - minimatch "3.1.2" - yup "0.32.11" - -"@verdaccio/core@6.0.0-6-next.60": - version "6.0.0-6-next.60" - resolved "https://registry.yarnpkg.com/@verdaccio/core/-/core-6.0.0-6-next.60.tgz#ece005b68be30e0220b0337210c89ce7b862aa3f" - integrity sha512-ZCDOPGjC1rox2dKwZ38GyWA3muA5JlTSfJ15EoIzd8kkWekGtV4/qtua0xUoxH4MhrYQmycsMuelaRveDtSz9A== - dependencies: - ajv "8.11.2" - core-js "3.27.0" - http-errors "1.8.1" - http-status-codes "2.2.0" - process-warning "1.0.0" - semver "7.3.8" - -"@verdaccio/core@6.0.0-6-next.61": - version "6.0.0-6-next.61" - resolved "https://registry.yarnpkg.com/@verdaccio/core/-/core-6.0.0-6-next.61.tgz#489aa487d5c69554eb1f5b9cd7bfa28bff8cf3e4" - integrity sha512-F5TLiQB9leeoZnyKRcE1hH5pr3lD2hZsKoda4ljqPyN2SqQq6ni6VsJLIMU73WjRQSl8GU9FPs8VunZo7l5AyA== - dependencies: - ajv "8.11.2" - core-js "3.27.0" - http-errors "1.8.1" - http-status-codes "2.2.0" - process-warning "1.0.0" - semver "7.3.8" - -"@verdaccio/file-locking@10.3.0": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@verdaccio/file-locking/-/file-locking-10.3.0.tgz#a4342665c549163817c267bfa451e32ed3009767" - integrity sha512-FE5D5H4wy/nhgR/d2J5e1Na9kScj2wMjlLPBHz7XF4XZAVSRdm45+kL3ZmrfA6b2HTADP/uH7H05/cnAYW8bhw== - dependencies: - lockfile "1.0.4" - -"@verdaccio/local-storage@10.3.1": - version "10.3.1" - resolved "https://registry.yarnpkg.com/@verdaccio/local-storage/-/local-storage-10.3.1.tgz#8cbdc6390a0eb532577ae217729cb0a4e062f299" - integrity sha512-f3oArjXPOAwUAA2dsBhfL/rSouqJ2sfml8k97RtnBPKOzisb28bgyAQW0mqwQvN4MTK5S/2xudmobFpvJAIatg== - dependencies: - "@verdaccio/commons-api" "10.2.0" - "@verdaccio/file-locking" "10.3.0" - "@verdaccio/streams" "10.2.0" - async "3.2.4" - debug "4.3.4" - lodash "4.17.21" - lowdb "1.0.0" - mkdirp "1.0.4" - -"@verdaccio/logger-7@6.0.0-6-next.6": - version "6.0.0-6-next.6" - resolved "https://registry.yarnpkg.com/@verdaccio/logger-7/-/logger-7-6.0.0-6-next.6.tgz#b07d005ff0c2b9b80ee0ad39aaa8903eba2cc708" - integrity sha512-Lkm/FCP5ALKfsje+y17FXnGpGI7mnAyzPlF+TA1ZkMXyVnRsQO0sbYfjOenkZ9/IpkEJzwq+15mzyvxZzVsWMA== - dependencies: - "@verdaccio/logger-commons" "6.0.0-6-next.29" - pino "7.11.0" - -"@verdaccio/logger-commons@6.0.0-6-next.29": - version "6.0.0-6-next.29" - resolved "https://registry.yarnpkg.com/@verdaccio/logger-commons/-/logger-commons-6.0.0-6-next.29.tgz#a79f0f7e512bdf947d36c11ca1bbafac3aedbb15" - integrity sha512-7AFWin5Kgurprr+7B/swOX4vbNxDWl/yzHAe6spSN3GXheX6mjsbgu8msovXvu0ntqehyEWeSgI30lOnB4vjKQ== - dependencies: - "@verdaccio/core" "6.0.0-6-next.61" - "@verdaccio/logger-prettify" "6.0.0-6-next.9" - colorette "2.0.19" - debug "4.3.4" - -"@verdaccio/logger-prettify@6.0.0-6-next.9": - version "6.0.0-6-next.9" - resolved "https://registry.yarnpkg.com/@verdaccio/logger-prettify/-/logger-prettify-6.0.0-6-next.9.tgz#614072d6a6edd5e462fb7eb697b78da5652183cf" - integrity sha512-+VZa/O4HgEGl5kuTUL86Nf3T5xrPBnrIPRMEiubW4Lytj2Jo9FTxxhAFyJ0QD4FSIZqyzi8Ul9jM0SKDxsTbdw== - dependencies: - colorette "2.0.19" - dayjs "1.11.7" - lodash "4.17.21" - pino-abstract-transport "1.0.0" - sonic-boom "3.2.1" - -"@verdaccio/middleware@6.0.0-6-next.40": - version "6.0.0-6-next.40" - resolved "https://registry.yarnpkg.com/@verdaccio/middleware/-/middleware-6.0.0-6-next.40.tgz#d3721341557ab52518052f449e4388223a161ae1" - integrity sha512-j7VT0sHM8OGEz2L1Tmff6oSjh8uHm40z96enUtFxpAJYELXx8KqGK82DHHl5FsCIB8GvdbFJn0YM1Bv4Gf5bvA== - dependencies: - "@verdaccio/config" "6.0.0-6-next.61" - "@verdaccio/core" "6.0.0-6-next.61" - "@verdaccio/url" "11.0.0-6-next.27" - "@verdaccio/utils" "6.0.0-6-next.29" - debug "4.3.4" - express "4.18.2" - express-rate-limit "5.5.1" - lodash "4.17.21" - lru-cache "7.14.1" - mime "2.6.0" - -"@verdaccio/streams@10.2.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/@verdaccio/streams/-/streams-10.2.0.tgz#e01d2bfdcfe8aa2389f31bc6b72a602628bd025b" - integrity sha512-FaIzCnDg0x0Js5kSQn1Le3YzDHl7XxrJ0QdIw5LrDUmLsH3VXNi4/NMlSHnw5RiTTMs4UbEf98V3RJRB8exqJA== - -"@verdaccio/tarball@11.0.0-6-next.30": - version "11.0.0-6-next.30" - resolved "https://registry.yarnpkg.com/@verdaccio/tarball/-/tarball-11.0.0-6-next.30.tgz#25e8aed952de1280e4d27412915173b79a023ff7" - integrity sha512-+lQn0FsPkuTrZnzWxJ9p1ZuQlctZoDuxqH5y6UoOJP49OJSEV14NrVIR0y8mRhgJRFOfBjyqDEoyH4gNkhnNoA== - dependencies: - "@verdaccio/core" "6.0.0-6-next.61" - "@verdaccio/url" "11.0.0-6-next.27" - "@verdaccio/utils" "6.0.0-6-next.29" - debug "4.3.4" - lodash "4.17.21" - -"@verdaccio/ui-theme@6.0.0-6-next.61": - version "6.0.0-6-next.61" - resolved "https://registry.yarnpkg.com/@verdaccio/ui-theme/-/ui-theme-6.0.0-6-next.61.tgz#7a076e1bbb875eb638f9e198e7f8f047f2c743dc" - integrity sha512-owS9KpIrG69KjJ5zoQa55qGQPQUKzcWN/giRk6lMpU8LXAKS0Ogpr86mzL4IgKg8DEHsfo0DWiBeWwXwr8HHFA== - -"@verdaccio/url@11.0.0-6-next.27": - version "11.0.0-6-next.27" - resolved "https://registry.yarnpkg.com/@verdaccio/url/-/url-11.0.0-6-next.27.tgz#3086c6fa2d0fa0844565e56b83b96366f32f31fd" - integrity sha512-Gj29AkqUZbpbGyN6vXxKejZt6lQBWhEmLHN6ajZgfmr/hqbTzx2VTetFIIFfuka72mHCOhnUn/hBFgh9fL1Hxw== - dependencies: - "@verdaccio/core" "6.0.0-6-next.61" - debug "4.3.4" - lodash "4.17.21" - validator "13.7.0" - -"@verdaccio/utils@6.0.0-6-next.28": - version "6.0.0-6-next.28" - resolved "https://registry.yarnpkg.com/@verdaccio/utils/-/utils-6.0.0-6-next.28.tgz#47982500940a89f2b786809ef31b4dbbdd759010" - integrity sha512-tEGIC7iYiDxZnrdBFB6O1cOdYOyeqE42MO4edtNLugbvAgh5iAntUI4qAGic8a39Od5JBm7QQ0RU3qHiofyU1w== - dependencies: - "@verdaccio/core" "6.0.0-6-next.60" - lodash "4.17.21" - minimatch "3.1.2" - semver "7.3.8" - -"@verdaccio/utils@6.0.0-6-next.29": - version "6.0.0-6-next.29" - resolved "https://registry.yarnpkg.com/@verdaccio/utils/-/utils-6.0.0-6-next.29.tgz#969e47a6a3f84d1276bb518e72ed6b20f7014cba" - integrity sha512-bIpZYaWTT+bKyUDyoTQxkGDd8us65o9OJtVLIKCrH2RKxpX5ONpwPCxemyFB8v5kErSbqRXXvvQQflbg3s+WHg== - dependencies: - "@verdaccio/core" "6.0.0-6-next.61" - lodash "4.17.21" - minimatch "3.1.2" - semver "7.3.8" - -"@vscode/debugprotocol@^1.51.0": - version "1.51.0" - resolved "https://registry.yarnpkg.com/@vscode/debugprotocol/-/debugprotocol-1.51.0.tgz#1d28a8581f8ea74b8e2fd465d4448717589a0ae3" - integrity sha512-39ShbKzI+0r53haLZQVEhY4XhdMJVSqfcliaDFigQjqiWattno5Ex0jXq2WRHrAtPf+W5Un9/HtED0K3pAiqZg== - -"@webassemblyjs/ast@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" - integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - -"@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" - integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== - dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - -"@webassemblyjs/floating-point-hex-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" - integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== - -"@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" - integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== - -"@webassemblyjs/helper-api-error@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" - integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== - -"@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" - integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== - -"@webassemblyjs/helper-buffer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" - integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== - -"@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" - integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== - -"@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" - integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" - integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== - -"@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" - integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== - dependencies: - "@webassemblyjs/ast" "1.9.0" - -"@webassemblyjs/helper-numbers@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" - integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/helper-wasm-bytecode@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" - integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== - -"@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" - integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== - -"@webassemblyjs/helper-wasm-section@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" - integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - -"@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" - integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - -"@webassemblyjs/ieee754@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" - integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" - integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" - integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" - integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" - integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== - -"@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" - integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== - -"@webassemblyjs/wasm-edit@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" - integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/helper-wasm-section" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-opt" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - "@webassemblyjs/wast-printer" "1.11.1" - -"@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" - integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/wasm-gen@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" - integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" - -"@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" - integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wasm-opt@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" - integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - -"@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" - integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - -"@webassemblyjs/wasm-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" - integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" - -"@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" - integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" - integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/wast-printer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" - integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" - integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@xtuc/long" "4.2.2" - -"@webpack-cli/configtest@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.0.4.tgz#f03ce6311c0883a83d04569e2c03c6238316d2aa" - integrity sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ== - -"@webpack-cli/info@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.3.0.tgz#9d78a31101a960997a4acd41ffd9b9300627fe2b" - integrity sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w== - dependencies: - envinfo "^7.7.3" - -"@webpack-cli/serve@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.5.1.tgz#b5fde2f0f79c1e120307c415a4c1d5eb15a6f278" - integrity sha512-4vSVUiOPJLmr45S8rMGy7WDvpWxfFxfP/Qx/cxZFCfvoypTYpPPL1X8VIZMe0WTA+Jr7blUxwUSEZNkjoMTgSw== - -"@webpack-contrib/schema-utils@^1.0.0-beta.0": - version "1.0.0-beta.0" - resolved "https://registry.yarnpkg.com/@webpack-contrib/schema-utils/-/schema-utils-1.0.0-beta.0.tgz#bf9638c9464d177b48209e84209e23bee2eb4f65" - integrity sha512-LonryJP+FxQQHsjGBi6W786TQB1Oym+agTpY0c+Kj8alnIw+DLUJb6SI8Y1GHGhLCH1yPRrucjObUmxNICQ1pg== - dependencies: - ajv "^6.1.0" - ajv-keywords "^3.1.0" - chalk "^2.3.2" - strip-ansi "^4.0.0" - text-table "^0.2.0" - webpack-log "^1.1.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - -"@yarnpkg/lockfile@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" - integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== - -JSONStream@1.3.5, JSONStream@^1.0.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -JSV@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/JSV/-/JSV-4.0.2.tgz#d077f6825571f82132f9dffaed587b4029feff57" - integrity sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c= - -abab@^2.0.3, abab@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" - integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -abstract-leveldown@^6.2.1, abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: - version "6.2.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" - integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== - dependencies: - buffer "^5.5.0" - immediate "^3.2.3" - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -accepts@~1.3.5, accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - -acorn@^6.4.1: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - -acorn@^7.1.1, acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.2.4, acorn@^8.4.1: - version "8.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" - integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== - -add-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" - integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= - -address@1.1.2, address@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" - integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== - -agent-base@6, agent-base@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -agentkeepalive@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" - integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ== - dependencies: - debug "^4.1.0" - depd "^1.1.2" - humanize-ms "^1.2.1" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -airbnb-js-shims@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz#db481102d682b98ed1daa4c5baa697a05ce5c040" - integrity sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ== - dependencies: - array-includes "^3.0.3" - array.prototype.flat "^1.2.1" - array.prototype.flatmap "^1.2.1" - es5-shim "^4.5.13" - es6-shim "^0.35.5" - function.prototype.name "^1.1.0" - globalthis "^1.0.0" - object.entries "^1.1.0" - object.fromentries "^2.0.0 || ^1.0.0" - object.getownpropertydescriptors "^2.0.3" - object.values "^1.1.0" - promise.allsettled "^1.0.0" - promise.prototype.finally "^3.1.0" - string.prototype.matchall "^4.0.0 || ^3.0.1" - string.prototype.padend "^3.0.0" - string.prototype.padstart "^3.0.0" - symbol.prototype.description "^1.0.0" - -ajv-errors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" - integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== - -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv@8.11.2: - version "8.11.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.2.tgz#aecb20b50607acf2569b6382167b65a96008bb78" - integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.7.0: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - 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" - -ansi-align@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" - integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== - dependencies: - string-width "^3.0.0" - -ansi-colors@^3.0.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" - integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-html@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" - integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-to-html@^0.6.11: - version "0.6.15" - resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.15.tgz#ac6ad4798a00f6aa045535d7f6a9cb9294eebea7" - integrity sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ== - dependencies: - entities "^2.0.0" - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -anymatch@^3.0.0, anymatch@^3.0.3, anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -apache-md5@1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/apache-md5/-/apache-md5-1.1.8.tgz#ea79c6feb03abfed42b2830dde06f75df5e3bbd9" - integrity sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA== - -app-root-dir@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/app-root-dir/-/app-root-dir-1.0.2.tgz#38187ec2dea7577fff033ffcb12172692ff6e118" - integrity sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg= - -aproba@^1.0.3, aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -aproba@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-differ@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" - integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== - -array-flat-polyfill@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-flat-polyfill/-/array-flat-polyfill-1.0.1.tgz#1e3a4255be619dfbffbfd1d635c1cf357cd034e7" - integrity sha512-hfJmKupmQN0lwi0xG6FQ5U8Rd97RnIERplymOv/qpq8AoNKPPAnxJadjFA23FNWm88wykh9HmpLJUUwUtNU/iw== - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -array-ify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" - integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= - -array-includes@^3.0.3, array-includes@^3.1.1, array-includes@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" - integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - get-intrinsic "^1.1.1" - is-string "^1.0.5" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -array.prototype.flat@^1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123" - integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - -array.prototype.flatmap@^1.2.1, array.prototype.flatmap@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" - integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - function-bind "^1.1.1" - -array.prototype.map@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array.prototype.map/-/array.prototype.map-1.0.3.tgz#1609623618d3d84134a37d4a220030c2bd18420b" - integrity sha512-nNcb30v0wfDyIe26Yif3PcV1JXQp4zEeEfupG7L4SRjnD6HLbO5b2a7eVSba53bOx4YCHYMBHt+Fp4vYstneRA== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.5" - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -arrify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== - -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -ast-types@0.9.6: - version "0.9.6" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" - integrity sha1-ECyenpAF0+fjgpvwxPok7oYu6bk= - -ast-types@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.14.2.tgz#600b882df8583e3cd4f2df5fa20fa83759d4bdfd" - integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== - dependencies: - tslib "^2.0.1" - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -async@0.9.x: - version "0.9.2" - resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" - integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= - -async@3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" - integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== - -async@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - dependencies: - lodash "^4.17.14" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -atomic-sleep@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" - integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== - -autoprefixer@^9.7.2: - version "9.8.6" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" - integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== - dependencies: - browserslist "^4.12.0" - caniuse-lite "^1.0.30001109" - colorette "^1.2.1" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.32" - postcss-value-parser "^4.1.0" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - -axe-core@3.5.5: - version "3.5.5" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227" - integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q== - -babel-code-frame@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-helper-evaluate-path@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c" - integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA== - -babel-helper-flip-expressions@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz#3696736a128ac18bc25254b5f40a22ceb3c1d3fd" - integrity sha1-NpZzahKKwYvCUlS19AoizrPB0/0= - -babel-helper-is-nodes-equiv@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684" - integrity sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ= - -babel-helper-is-void-0@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz#7d9c01b4561e7b95dbda0f6eee48f5b60e67313e" - integrity sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4= - -babel-helper-mark-eval-scopes@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562" - integrity sha1-0kSjvvmESHJgP/tG4izorN9VFWI= - -babel-helper-remove-or-void@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60" - integrity sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA= - -babel-helper-to-multiple-sequence-expressions@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d" - integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA== - -babel-jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" - integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== - 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" - -babel-loader@^8.0.6: - version "8.2.2" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" - integrity sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g== - dependencies: - find-cache-dir "^3.3.1" - loader-utils "^1.4.0" - make-dir "^3.1.0" - schema-utils "^2.6.5" - -babel-plugin-add-react-displayname@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz#339d4cddb7b65fd62d1df9db9fe04de134122bd5" - integrity sha1-M51M3be2X9YtHfnbn+BN4TQSK9U= - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - -babel-plugin-emotion@^10.0.20, babel-plugin-emotion@^10.0.27: - version "10.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz#a1fe3503cff80abfd0bdda14abd2e8e57a79d17d" - integrity sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@emotion/hash" "0.8.0" - "@emotion/memoize" "0.7.4" - "@emotion/serialize" "^0.11.16" - babel-plugin-macros "^2.0.0" - babel-plugin-syntax-jsx "^6.18.0" - convert-source-map "^1.5.0" - escape-string-regexp "^1.0.5" - find-root "^1.1.0" - source-map "^0.5.7" - -babel-plugin-istanbul@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" - integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== - 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" - -babel-plugin-jest-hoist@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" - integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - -babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" - integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== - dependencies: - "@babel/runtime" "^7.7.2" - cosmiconfig "^6.0.0" - resolve "^1.12.0" - -babel-plugin-minify-builtins@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b" - integrity sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag== - -babel-plugin-minify-constant-folding@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz#f84bc8dbf6a561e5e350ff95ae216b0ad5515b6e" - integrity sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ== - dependencies: - babel-helper-evaluate-path "^0.5.0" - -babel-plugin-minify-dead-code-elimination@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz#1a0c68e44be30de4976ca69ffc535e08be13683f" - integrity sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg== - dependencies: - babel-helper-evaluate-path "^0.5.0" - babel-helper-mark-eval-scopes "^0.4.3" - babel-helper-remove-or-void "^0.4.3" - lodash "^4.17.11" - -babel-plugin-minify-flip-comparisons@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz#00ca870cb8f13b45c038b3c1ebc0f227293c965a" - integrity sha1-AMqHDLjxO0XAOLPB68DyJyk8llo= - dependencies: - babel-helper-is-void-0 "^0.4.3" - -babel-plugin-minify-guarded-expressions@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz#818960f64cc08aee9d6c75bec6da974c4d621135" - integrity sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA== - dependencies: - babel-helper-evaluate-path "^0.5.0" - babel-helper-flip-expressions "^0.4.3" - -babel-plugin-minify-infinity@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz#dfb876a1b08a06576384ef3f92e653ba607b39ca" - integrity sha1-37h2obCKBldjhO8/kuZTumB7Oco= - -babel-plugin-minify-mangle-names@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz#bcddb507c91d2c99e138bd6b17a19c3c271e3fd3" - integrity sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw== - dependencies: - babel-helper-mark-eval-scopes "^0.4.3" - -babel-plugin-minify-numeric-literals@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz#8e4fd561c79f7801286ff60e8c5fd9deee93c0bc" - integrity sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw= - -babel-plugin-minify-replace@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz#d3e2c9946c9096c070efc96761ce288ec5c3f71c" - integrity sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q== - -babel-plugin-minify-simplify@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz#f21613c8b95af3450a2ca71502fdbd91793c8d6a" - integrity sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A== - dependencies: - babel-helper-evaluate-path "^0.5.0" - babel-helper-flip-expressions "^0.4.3" - babel-helper-is-nodes-equiv "^0.0.1" - babel-helper-to-multiple-sequence-expressions "^0.5.0" - -babel-plugin-minify-type-constructors@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz#1bc6f15b87f7ab1085d42b330b717657a2156500" - integrity sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA= - dependencies: - babel-helper-is-void-0 "^0.4.3" - -babel-plugin-named-asset-import@^0.3.1: - version "0.3.7" - resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz#156cd55d3f1228a5765774340937afc8398067dd" - integrity sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw== - -babel-plugin-polyfill-corejs2@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" - integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ== - dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.2.2" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.2.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.3.tgz#72add68cf08a8bf139ba6e6dfc0b1d504098e57b" - integrity sha512-rCOFzEIJpJEAU14XCcV/erIf/wZQMmMT5l5vXOpL5uoznyOGfDIjPj6FVytMvtzaKSTSVKouOCTPJ5OMUZH30g== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.2" - core-js-compat "^3.14.0" - -babel-plugin-polyfill-regenerator@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077" - integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.2" - -babel-plugin-react-docgen@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz#7cc8e2f94e8dc057a06e953162f0810e4e72257b" - integrity sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ== - dependencies: - ast-types "^0.14.2" - lodash "^4.17.15" - react-docgen "^5.0.0" - -babel-plugin-syntax-jsx@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" - integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= - -babel-plugin-transform-inline-consecutive-adds@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz#323d47a3ea63a83a7ac3c811ae8e6941faf2b0d1" - integrity sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE= - -babel-plugin-transform-member-expression-literals@^6.9.4: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf" - integrity sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8= - -babel-plugin-transform-merge-sibling-variables@^6.9.4: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz#85b422fc3377b449c9d1cde44087203532401dae" - integrity sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4= - -babel-plugin-transform-minify-booleans@^6.9.4: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198" - integrity sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg= - -babel-plugin-transform-property-literals@^6.9.4: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39" - integrity sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk= - dependencies: - esutils "^2.0.2" - -babel-plugin-transform-regexp-constructors@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz#58b7775b63afcf33328fae9a5f88fbd4fb0b4965" - integrity sha1-WLd3W2OvzzMyj66aX4j71PsLSWU= - -babel-plugin-transform-remove-console@^6.9.4: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780" - integrity sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A= - -babel-plugin-transform-remove-debugger@^6.9.4: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2" - integrity sha1-QrcnYxyXl44estGZp67IShgznvI= - -babel-plugin-transform-remove-undefined@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz#80208b31225766c630c97fa2d288952056ea22dd" - integrity sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ== - dependencies: - babel-helper-evaluate-path "^0.5.0" - -babel-plugin-transform-simplify-comparison-operators@^6.9.4: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9" - integrity sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk= - -babel-plugin-transform-undefined-to-void@^6.9.4: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280" - integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA= - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - 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" - -babel-preset-jest@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" - integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== - dependencies: - babel-plugin-jest-hoist "^26.6.2" - babel-preset-current-node-syntax "^1.0.0" - -"babel-preset-minify@^0.5.0 || 0.6.0-alpha.5": - version "0.5.1" - resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz#25f5d0bce36ec818be80338d0e594106e21eaa9f" - integrity sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg== - dependencies: - babel-plugin-minify-builtins "^0.5.0" - babel-plugin-minify-constant-folding "^0.5.0" - babel-plugin-minify-dead-code-elimination "^0.5.1" - babel-plugin-minify-flip-comparisons "^0.4.3" - babel-plugin-minify-guarded-expressions "^0.4.4" - babel-plugin-minify-infinity "^0.4.3" - babel-plugin-minify-mangle-names "^0.5.0" - babel-plugin-minify-numeric-literals "^0.4.3" - babel-plugin-minify-replace "^0.5.0" - babel-plugin-minify-simplify "^0.5.1" - babel-plugin-minify-type-constructors "^0.4.3" - babel-plugin-transform-inline-consecutive-adds "^0.4.3" - babel-plugin-transform-member-expression-literals "^6.9.4" - babel-plugin-transform-merge-sibling-variables "^6.9.4" - babel-plugin-transform-minify-booleans "^6.9.4" - babel-plugin-transform-property-literals "^6.9.4" - babel-plugin-transform-regexp-constructors "^0.4.3" - babel-plugin-transform-remove-console "^6.9.4" - babel-plugin-transform-remove-debugger "^6.9.4" - babel-plugin-transform-remove-undefined "^0.5.0" - babel-plugin-transform-simplify-comparison-operators "^6.9.4" - babel-plugin-transform-undefined-to-void "^6.9.4" - lodash "^4.17.11" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base16@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" - integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= - -base64-js@^1.0.2, base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - 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" - -basic-auth@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" - integrity sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ= - -batch-processor@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/batch-processor/-/batch-processor-1.0.0.tgz#75c95c32b748e0850d10c2b168f6bdbe9891ace8" - integrity sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg= - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -bcryptjs@2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" - integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= - -before-after-hook@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" - integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== - -better-opn@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/better-opn/-/better-opn-2.1.1.tgz#94a55b4695dc79288f31d7d0e5f658320759f7c6" - integrity sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA== - dependencies: - open "^7.0.3" - -bfj@^6.1.1: - version "6.1.2" - resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.2.tgz#325c861a822bcb358a41c78a33b8e6e2086dde7f" - integrity sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw== - dependencies: - bluebird "^3.5.5" - check-types "^8.0.3" - hoopy "^0.1.4" - tryer "^1.0.1" - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -blacklist@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/blacklist/-/blacklist-1.1.4.tgz#b2dd09d6177625b2caa69835a37b28995fa9a2f2" - integrity sha1-st0J1hd2JbLKppg1o3somV+povI= - -bluebird@^3.3.5, bluebird@^3.5.5: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - -body-parser@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - -boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -boxen@^4.1.0, boxen@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" - integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== - dependencies: - ansi-align "^3.0.0" - camelcase "^5.3.1" - chalk "^3.0.0" - cli-boxes "^2.2.0" - string-width "^4.1.0" - term-size "^2.1.0" - type-fest "^0.8.1" - widest-line "^3.1.0" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - 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" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@4.10.0: - version "4.10.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.10.0.tgz#f179737913eaf0d2b98e4926ac1ca6a15cbcc6a9" - integrity sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA== - dependencies: - caniuse-lite "^1.0.30001035" - electron-to-chromium "^1.3.378" - node-releases "^1.1.52" - pkg-up "^3.1.0" - -browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.6: - version "4.16.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" - integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== - 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" - -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= - -buffer-from@1.x, buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -buffer@^5.5.0, buffer@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -builtins@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" - integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= - -byline@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" - integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= - -byte-size@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" - integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -c8@^7.6.0: - version "7.7.3" - resolved "https://registry.yarnpkg.com/c8/-/c8-7.7.3.tgz#5af8f83b55dace03b353375e7a2ba85e2c13b17f" - integrity sha512-ZyA7n3w8i4ETV25tVYMHwJxCSnaOf/LfA8vOcuZOPbonuQfD7tBT/gMWZy7eczRpCDuHcvMXwoqAemg6R0p3+A== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@istanbuljs/schema" "^0.1.2" - find-up "^5.0.0" - foreground-child "^2.0.0" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-report "^3.0.0" - istanbul-reports "^3.0.2" - rimraf "^3.0.0" - test-exclude "^6.0.0" - v8-to-istanbul "^8.0.0" - yargs "^16.2.0" - yargs-parser "^20.2.7" - -cacache@^12.0.2: - version "12.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^15.0.5, cacache@^15.2.0: - version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== - dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - 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" - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camel-case@3.0.x: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" - integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= - dependencies: - no-case "^2.2.0" - upper-case "^1.1.1" - -camel-case@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" - integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== - dependencies: - pascal-case "^3.1.2" - tslib "^2.0.3" - -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - -camelcase@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0, camelcase@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== - -caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001219: - version "1.0.30001243" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001243.tgz#d9250155c91e872186671c523f3ae50cfc94a3aa" - integrity sha512-vNxw9mkTBtkmLFnJRv/2rhs1yufpDfCkBZexG3Y0xdOH2Z/eE/85E4Dl5j1YUN34nZVsSp6vVRFQRrez9wJMRA== - -canonicalize@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/canonicalize/-/canonicalize-1.0.5.tgz#b43b390ce981d397908bb847c3a8d9614323a47b" - integrity sha512-mAjKJPIyP0xqqv6IAkvso07StOmz6cmGtNDg3pXCSzXVZOqka7StIkAhJl/zHOi4M2CgpYfD6aeRWbnrmtvBEA== - -canvas@^2.6.1: - version "2.11.0" - resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.0.tgz#7f0c3e9ae94cf469269b5d3a7963a7f3a9936434" - integrity sha512-bdTjFexjKJEwtIo0oRx8eD4G2yWoUOXP9lj279jmQ2zMnTQhT8C3512OKz3s+ZOaQlLbE7TuVvRDYDB3Llyy5g== - dependencies: - "@mapbox/node-pre-gyp" "^1.0.0" - nan "^2.17.0" - simple-get "^3.0.3" - -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" - -case-sensitive-paths-webpack-plugin@^2.2.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" - integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - 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" - -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" - integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== - -character-entities@^1.0.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== - -character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== - -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -charenc@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" - integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= - -check-types@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" - integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ== - -child_process@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/child_process/-/child_process-1.0.2.tgz#b1f7e7fc73d25e7fd1d455adc94e143830182b5a" - integrity sha1-sffn/HPSXn/R1FWtyU4UODAYK1o= - -chokidar@^2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -chokidar@^3.3.0, chokidar@^3.4.0, chokidar@^3.4.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - -chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - -chrome-launcher@^0.13.3: - version "0.13.4" - resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.13.4.tgz#4c7d81333c98282899c4e38256da23e00ed32f73" - integrity sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A== - dependencies: - "@types/node" "*" - escape-string-regexp "^1.0.5" - is-wsl "^2.2.0" - lighthouse-logger "^1.0.0" - mkdirp "^0.5.3" - rimraf "^3.0.2" - -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -cjs-module-lexer@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" - integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -classnames@^2.2, classnames@^2.2.5: - version "2.3.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== - -clean-css@4.2.x, clean-css@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" - integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== - dependencies: - source-map "~0.6.0" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-boxes@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" - integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-table3@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.0.tgz#b7b1bc65ca8e7b5cef9124e13dc2b21e2ce4faee" - integrity sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ== - dependencies: - object-assign "^4.1.0" - string-width "^4.2.0" - optionalDependencies: - colors "^1.1.2" - -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -clipanion@3.2.0-rc.14: - version "3.2.0-rc.14" - resolved "https://registry.yarnpkg.com/clipanion/-/clipanion-3.2.0-rc.14.tgz#d98154a74ae533a940de1af041e6246ba9725f0e" - integrity sha512-lj5zydbH786t6gpXe6oNX7CM5YKhd0CDhcXG8pKyRa2Nz5cgj1yhnNKxDi/MyPYwjyvAG5oVBeDdYCGUAgD8lQ== - dependencies: - typanion "^3.8.0" - -clipboard@^2.0.0: - version "2.0.8" - resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba" - integrity sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ== - dependencies: - good-listener "^1.2.2" - select "^1.1.2" - tiny-emitter "^2.0.0" - -cliui@^3.0.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -clone@~2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= - -clsx@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" - integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== - -cmd-shim@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" - integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== - dependencies: - mkdirp-infer-owner "^2.0.0" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -coa@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -codemirror@~5.61.0: - version "5.61.1" - resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.61.1.tgz#ccfc8a43b8fcfb8b12e8e75b5ffde48d541406e0" - integrity sha512-+D1NZjAucuzE93vJGbAaXzvoBHwp9nJZWWWF9utjv25+5AZUiah6CIlfb4ikG4MoDsFsCG8niiJH5++OO2LgIQ== - -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0, color-convert@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.5.4: - version "1.5.5" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014" - integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e" - integrity sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.4" - -colorette@2.0.19: - version "2.0.19" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" - integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== - -colorette@^1.2.1, colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== - -colors@^1.1.2, colors@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - -columnify@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" - integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= - dependencies: - strip-ansi "^3.0.0" - wcwidth "^1.0.0" - -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -comma-separated-tokens@^1.0.0: - version "1.0.8" - resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" - integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== - -commander@2, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@2.17.x: - version "2.17.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" - integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== - -commander@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - -commander@^5.0.0, commander@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" - integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== - -commander@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - -commander@~2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== - -commander@~6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.0.0.tgz#2b270da94f8fb9014455312f829a1129dbf8887e" - integrity sha512-s7EA+hDtTYNhuXkTlhqew4txMZVdszBmKWSPEMxGr8ru8JXR7bLUFIAtPhcSuFdJQ0ILMxnJi8GkQL0yvDy/YA== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -compare-func@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" - integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== - dependencies: - array-ify "^1.0.0" - dot-prop "^5.1.0" - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -compute-gcd@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/compute-gcd/-/compute-gcd-1.2.1.tgz#34d639f3825625e1357ce81f0e456a6249d8c77f" - integrity sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg== - dependencies: - validate.io-array "^1.0.3" - validate.io-function "^1.0.2" - validate.io-integer-array "^1.0.0" - -compute-lcm@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/compute-lcm/-/compute-lcm-1.1.2.tgz#9107c66b9dca28cefb22b4ab4545caac4034af23" - integrity sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ== - dependencies: - compute-gcd "^1.2.1" - validate.io-array "^1.0.3" - validate.io-function "^1.0.2" - validate.io-integer-array "^1.0.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -concat-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" - integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.0.2" - typedarray "^0.0.6" - -config-chain@^1.1.12: - version "1.1.13" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" - integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - -configstore@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" - integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== - dependencies: - dot-prop "^5.2.0" - graceful-fs "^4.1.2" - make-dir "^3.0.0" - unique-string "^2.0.0" - write-file-atomic "^3.0.0" - xdg-basedir "^4.0.0" - -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== - dependencies: - safe-buffer "5.1.2" - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -conventional-changelog-angular@^5.0.12: - version "5.0.12" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz#c979b8b921cbfe26402eb3da5bbfda02d865a2b9" - integrity sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw== - dependencies: - compare-func "^2.0.0" - q "^1.5.1" - -conventional-changelog-core@^4.2.2: - version "4.2.3" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.3.tgz#ce44d4bbba4032e3dc14c00fcd5b53fc00b66433" - integrity sha512-MwnZjIoMRL3jtPH5GywVNqetGILC7g6RQFvdb8LRU/fA/338JbeWAku3PZ8yQ+mtVRViiISqJlb0sOz0htBZig== - dependencies: - add-stream "^1.0.0" - conventional-changelog-writer "^5.0.0" - conventional-commits-parser "^3.2.0" - dateformat "^3.0.0" - get-pkg-repo "^4.0.0" - git-raw-commits "^2.0.8" - git-remote-origin-url "^2.0.0" - git-semver-tags "^4.1.1" - lodash "^4.17.15" - normalize-package-data "^3.0.0" - q "^1.5.1" - read-pkg "^3.0.0" - read-pkg-up "^3.0.0" - through2 "^4.0.0" - -conventional-changelog-preset-loader@^2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" - integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== - -conventional-changelog-writer@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz#c4042f3f1542f2f41d7d2e0d6cad23aba8df8eec" - integrity sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g== - dependencies: - conventional-commits-filter "^2.0.7" - dateformat "^3.0.0" - handlebars "^4.7.6" - json-stringify-safe "^5.0.1" - lodash "^4.17.15" - meow "^8.0.0" - semver "^6.0.0" - split "^1.0.0" - through2 "^4.0.0" - -conventional-commits-filter@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" - integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== - dependencies: - lodash.ismatch "^4.4.0" - modify-values "^1.0.0" - -conventional-commits-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2" - integrity sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA== - dependencies: - JSONStream "^1.0.4" - is-text-path "^1.0.1" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - trim-off-newlines "^1.0.0" - -conventional-recommended-bump@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" - integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== - dependencies: - concat-stream "^2.0.0" - conventional-changelog-preset-loader "^2.3.4" - conventional-commits-filter "^2.0.7" - conventional-commits-parser "^3.2.0" - git-raw-commits "^2.0.8" - git-semver-tags "^4.1.1" - meow "^8.0.0" - q "^1.5.1" - -convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== - -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - -cookies@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" - integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow== - dependencies: - depd "~2.0.0" - keygrip "~1.1.0" - -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -copy-to-clipboard@^3.0.8: - version "3.3.1" - resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" - integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== - dependencies: - toggle-selection "^1.0.6" - -copy-webpack-plugin@^6.0.1: - version "6.4.1" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz#138cd9b436dbca0a6d071720d5414848992ec47e" - integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA== - dependencies: - cacache "^15.0.5" - fast-glob "^3.2.4" - find-cache-dir "^3.3.1" - glob-parent "^5.1.1" - globby "^11.0.1" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" - -core-js-compat@^3.14.0, core-js-compat@^3.15.0: - version "3.15.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.15.2.tgz#47272fbb479880de14b4e6081f71f3492f5bd3cb" - integrity sha512-Wp+BJVvwopjI+A1EFqm2dwUmWYXrvucmtIB2LgXn/Rb+gWPKYxtmb4GKHGKG/KGF1eK9jfjzT38DITbTOCX/SQ== - dependencies: - browserslist "^4.16.6" - semver "7.0.0" - -core-js-pure@^3.0.1, core-js-pure@^3.6.5: - version "3.21.0" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.0.tgz#819adc8dfb808205ce25b51d50591becd615db7e" - integrity sha512-VaJUunCZLnxuDbo1rNOzwbet9E1K9joiXS5+DQMPtgxd24wfsZbJZMMfQLGYMlCUvSxLfsRUUhoOR2x28mFfeg== - -core-js@3.27.0: - version "3.27.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.0.tgz#a343bc614f29d9dcffa7616e65e10f9001cdd332" - integrity sha512-wY6cKosevs430KRkHUIsvepDXHGjlXOZO3hYXNyqpD6JvB0X28aXyv0t1Y1vZMwE7SoKmtfa6IASHCPN52FwBQ== - -core-js@^3.0.1, core-js@^3.0.4, core-js@^3.6.5: - version "3.15.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.15.2.tgz#740660d2ff55ef34ce664d7e2455119c5bdd3d61" - integrity sha512-tKs41J7NJVuaya8DxIOCnl8QuPHx5/ZVbFo1oKgVl1qHFBBrDctzQGtuLjPpRdNTWmKPH6oEvgN/MUID+l485Q== - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cors@2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - -corser@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" - integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c= - -cosmiconfig@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - -cosmiconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" - integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -create-react-class@^15.6.2: - version "15.7.0" - resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e" - integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng== - dependencies: - loose-envify "^1.3.1" - object-assign "^4.1.1" - -create-react-context@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c" - integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw== - dependencies: - gud "^1.0.0" - warning "^4.0.3" - -cross-spawn@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" - integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - 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" - -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypt@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - -crypto@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" - integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== - -css-loader@^3.5.3: - version "3.6.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645" - integrity sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ== - dependencies: - camelcase "^5.3.1" - cssesc "^3.0.0" - icss-utils "^4.1.1" - loader-utils "^1.2.3" - normalize-path "^3.0.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" - postcss-value-parser "^4.1.0" - schema-utils "^2.7.0" - semver "^6.3.0" - -css-loader@^5.0.1: - version "5.2.6" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.6.tgz#c3c82ab77fea1f360e587d871a6811f4450cc8d1" - integrity sha512-0wyN5vXMQZu6BvjbrPdUJvkCzGEO24HC7IS7nW4llc6BBFC+zwR9CKtYGv63Puzsg10L/o12inMY5/2ByzfD6w== - dependencies: - icss-utils "^5.1.0" - loader-utils "^2.0.0" - postcss "^8.2.15" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^3.0.0" - semver "^7.3.5" - -css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - -css-select@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== - dependencies: - boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" - -css-select@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" - integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== - dependencies: - boolbase "^1.0.0" - css-what "^5.0.0" - domhandler "^4.2.0" - domutils "^2.6.0" - nth-check "^2.0.0" - -css-tree@1.0.0-alpha.37: - version "1.0.0-alpha.37" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" - integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== - dependencies: - mdn-data "2.0.4" - source-map "^0.6.1" - -css-tree@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - -css-what@^3.2.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" - integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== - -css-what@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" - integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -csso@^4.0.2: - version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== - dependencies: - css-tree "^1.1.2" - -cssom@0.3.x, cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - -cssstyle@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.2.1.tgz#3aceb2759eaf514ac1a21628d723d6043a819495" - integrity sha512-7DYm8qe+gPx/h77QlCyFmX80+fGaE/6A/Ekl0zaszYOubvySO2saYFdQ78P29D0UsULxFKCetDGNaNRUdSF+2A== - dependencies: - cssom "0.3.x" - -cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - -csstype@2.6.9, csstype@^2.5.7: - version "2.6.9" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098" - integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q== - -csstype@^3.0.2, csstype@~3.0.3: - version "3.0.8" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" - integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== - -csv-spectrum@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/csv-spectrum/-/csv-spectrum-1.0.0.tgz#591ac9ff48ad4f3eb4338457bc9801b349e3d628" - integrity sha1-WRrJ/0itTz60M4RXvJgBs0nj1ig= - -cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - -"d3-array@1 - 2", d3-array@2, d3-array@^2.3.0, d3-array@^2.5.0, d3-array@^2.7.1: - version "2.12.1" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" - integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== - dependencies: - internmap "^1.0.0" - -"d3-color@1 - 2", d3-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" - integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== - -d3-delaunay@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-5.3.0.tgz#b47f05c38f854a4e7b3cea80e0bb12e57398772d" - integrity sha512-amALSrOllWVLaHTnDLHwMIiz0d1bBu9gZXd1FiLfXf8sHcX9jrcj81TVZOqD4UX7MgBZZ07c8GxzEgBpJqc74w== - dependencies: - delaunator "4" - -"d3-dispatch@1 - 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-2.0.0.tgz#8a18e16f76dd3fcaef42163c97b926aa9b55e7cf" - integrity sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA== - -d3-dsv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-2.0.0.tgz#b37b194b6df42da513a120d913ad1be22b5fe7c5" - integrity sha512-E+Pn8UJYx9mViuIUkoc93gJGGYut6mSDKy2+XaPwccwkRGlR+LO97L2VCCRjQivTwLHkSnAJG7yo00BWY6QM+w== - dependencies: - commander "2" - iconv-lite "0.4" - rw "1" - -d3-force@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-2.1.1.tgz#f20ccbf1e6c9e80add1926f09b51f686a8bc0937" - integrity sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew== - dependencies: - d3-dispatch "1 - 2" - d3-quadtree "1 - 2" - d3-timer "1 - 2" - -"d3-format@1 - 2", d3-format@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767" - integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== - -d3-geo-projection@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-geo-projection/-/d3-geo-projection-3.0.0.tgz#45ad8ce756cdbfa8340b11b2988644d8e1fa42e4" - integrity sha512-1JE+filVbkEX2bT25dJdQ05iA4QHvUwev6o0nIQHOSrNlHCAKfVss/U10vEM3pA4j5v7uQoFdQ4KLbx9BlEbWA== - dependencies: - commander "2" - d3-array "1 - 2" - d3-geo "1.12.0 - 2" - resolve "^1.1.10" - -"d3-geo@1.12.0 - 2", d3-geo@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-2.0.2.tgz#c065c1b71fe8c5f1be657e5f43d9bdd010383c40" - integrity sha512-8pM1WGMLGFuhq9S+FpPURxic+gKzjluCD/CHTuUF3mXMeiCo0i6R0tO1s4+GArRFde96SLcW/kOFRjoAosPsFA== - dependencies: - d3-array "^2.5.0" - -d3-hierarchy@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-2.0.0.tgz#dab88a58ca3e7a1bc6cab390e89667fcc6d20218" - integrity sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw== - -"d3-interpolate@1.2.0 - 2", d3-interpolate@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163" - integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== - dependencies: - d3-color "1 - 2" - -"d3-path@1 - 2", d3-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-2.0.0.tgz#55d86ac131a0548adae241eebfb56b4582dd09d8" - integrity sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA== - -"d3-quadtree@1 - 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-2.0.0.tgz#edbad045cef88701f6fee3aee8e93fb332d30f9d" - integrity sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw== - -d3-scale@^3.2.2: - version "3.3.0" - resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3" - integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ== - dependencies: - d3-array "^2.3.0" - d3-format "1 - 2" - d3-interpolate "1.2.0 - 2" - d3-time "^2.1.1" - d3-time-format "2 - 3" - -d3-shape@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-2.1.0.tgz#3b6a82ccafbc45de55b57fcf956c584ded3b666f" - integrity sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA== - dependencies: - d3-path "1 - 2" - -"d3-time-format@2 - 3", d3-time-format@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6" - integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== - dependencies: - d3-time "1 - 2" - -"d3-time@1 - 2", d3-time@^2.0.0, d3-time@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682" - integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ== - dependencies: - d3-array "2" - -"d3-timer@1 - 2", d3-timer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-2.0.0.tgz#055edb1d170cfe31ab2da8968deee940b56623e6" - integrity sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA== - -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - -dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - -dateformat@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" - integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== - -dayjs@1.11.7: - version "1.11.7" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" - integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ== - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - -debug@4.3.4, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^3.0.0, debug@^3.1.1: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debuglog@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= - -decamelize-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - -decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decimal.js@^10.2.1: - version "10.3.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" - integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - -decompress-response@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" - integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== - dependencies: - mimic-response "^2.0.0" - -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= - -deep-equal@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -deep-is@^0.1.3, deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -deep-object-diff@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" - integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - -deferred-leveldown@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" - integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== - dependencies: - abstract-leveldown "~6.2.1" - inherits "^2.0.3" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -delaunator@4: - version "4.0.1" - resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-4.0.1.tgz#3d779687f57919a7a418f8ab947d3bddb6846957" - integrity sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag== - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -delegate@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" - integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -depd@2.0.0, depd@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -depd@^1.1.2, depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -dependency-graph@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.9.0.tgz#11aed7e203bc8b00f48356d92db27b265c445318" - integrity sha512-9YLIBURXj4DJMFALxXw9K3Y3rwb5Fk0X5/8ipCzaN84+gKxoHK43tVKRNakCQbiEx07E8Uwhuq21BpUagFhZ8w== - -deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -details-element-polyfill@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/details-element-polyfill/-/details-element-polyfill-2.4.0.tgz#e0622adef7902662faf27b4ab8acba5dc4e3a6e6" - integrity sha512-jnZ/m0+b1gz3EcooitqL7oDEkKHEro659dt8bWB/T/HjiILucoQhHvvi5MEOAIFJXxxO+rIYJ/t3qCgfUOSU5g== - -detect-indent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" - integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= - -detect-indent@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" - integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== - -detect-libc@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - -detect-newline@3.1.0, detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -detect-port-alt@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" - integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== - dependencies: - address "^1.0.1" - debug "^2.6.0" - -detect-port@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" - integrity sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ== - dependencies: - address "^1.0.1" - debug "^2.6.0" - -dezalgo@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= - dependencies: - asap "^2.0.0" - wrappy "1" - -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" - integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== - dependencies: - arrify "^1.0.1" - path-type "^3.0.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dom-converter@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" - integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== - dependencies: - utila "~0.4" - -dom-helpers@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8" - integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== - dependencies: - "@babel/runtime" "^7.1.2" - -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - -dom-serializer@^1.0.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" - integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - -dom4@^2.1.5: - version "2.1.6" - resolved "https://registry.yarnpkg.com/dom4/-/dom4-2.1.6.tgz#c90df07134aa0dbd81ed4d6ba1237b36fc164770" - integrity sha512-JkCVGnN4ofKGbjf5Uvc8mmxaATIErKQKSgACdBXpsQ3fY6DlIpAyWfiBSrGkttATssbDCp3psiAKWXk5gmjycA== - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== - -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - -domhandler@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a" - integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA== - dependencies: - domelementtype "^2.0.1" - -domhandler@^4.0.0, domhandler@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059" - integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA== - dependencies: - domelementtype "^2.2.0" - -domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^2.0.0, domutils@^2.5.2, domutils@^2.6.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442" - integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - -dot-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" - integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -dot-prop@^5.1.0, dot-prop@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -dot-prop@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" - integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== - dependencies: - is-obj "^2.0.0" - -dotenv-defaults@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/dotenv-defaults/-/dotenv-defaults-1.1.1.tgz#032c024f4b5906d9990eb06d722dc74cc60ec1bd" - integrity sha512-6fPRo9o/3MxKvmRZBD3oNFdxODdhJtIy1zcJeUSCs6HCy4tarUpd+G67UTU9tF6OWXeSPqsm4fPAB+2eY9Rt9Q== - dependencies: - dotenv "^6.2.0" - -dotenv-expand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" - integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== - -dotenv-webpack@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/dotenv-webpack/-/dotenv-webpack-1.8.0.tgz#7ca79cef2497dd4079d43e81e0796bc9d0f68a5e" - integrity sha512-o8pq6NLBehtrqA8Jv8jFQNtG9nhRtVqmoD4yWbgUyoU3+9WBlPe+c2EAiaJok9RB28QvrWvdWLZGeTT5aATDMg== - dependencies: - dotenv-defaults "^1.0.2" - -dotenv@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" - integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w== - -dotenv@^8.0.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - -duplexer@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -duplexify@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" - integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw== - dependencies: - end-of-stream "^1.4.1" - inherits "^2.0.3" - readable-stream "^3.1.1" - stream-shift "^1.0.0" - -duplicate-package-checker-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/duplicate-package-checker-webpack-plugin/-/duplicate-package-checker-webpack-plugin-3.0.0.tgz#78bb89e625fa7cf8c2a59c53f62b495fda9ba287" - integrity sha512-aO50/qPC7X2ChjRFniRiscxBLT/K01bALqfcDaf8Ih5OqQ1N4iT/Abx9Ofu3/ms446vHTm46FACIuJUmgUQcDQ== - dependencies: - chalk "^2.3.0" - find-root "^1.0.0" - lodash "^4.17.4" - semver "^5.4.1" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ecdsa-sig-formatter@1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" - integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== - dependencies: - safe-buffer "^5.0.1" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -ejs@^2.6.1: - version "2.7.4" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" - integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== - -ejs@^3.1.2: - version "3.1.6" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a" - integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw== - dependencies: - jake "^10.6.1" - -electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.723: - version "1.3.771" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.771.tgz#c4aa601e6420e11926095f75fe803956a1b4bd81" - integrity sha512-zHMomTqkpnAD9W5rhXE1aiU3ogGFrqWzdvM4C6222SREiqsWQb2w0S7P2Ii44qCaGimmAP1z+OydllM438uJyA== - -element-resize-detector@^1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/element-resize-detector/-/element-resize-detector-1.2.3.tgz#5078d9b99398fe4c589f8c8df94ff99e5d413ff3" - integrity sha512-+dhNzUgLpq9ol5tyhoG7YLoXL3ssjfFW+0gpszXPwRU6NjGr1fVHMEAF8fVzIiRJq57Nre0RFeIjJwI8Nh2NmQ== - dependencies: - batch-processor "1.0.0" - -elliptic@^6.5.3: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emittery@^0.7.1: - version "0.7.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" - integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -emotion-theming@^10.0.19: - version "10.0.27" - resolved "https://registry.yarnpkg.com/emotion-theming/-/emotion-theming-10.0.27.tgz#1887baaec15199862c89b1b984b79806f2b9ab10" - integrity sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw== - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/weak-memoize" "0.2.5" - hoist-non-react-statics "^3.3.0" - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -encoding-down@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" - integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== - dependencies: - abstract-leveldown "^6.2.1" - inherits "^2.0.3" - level-codec "^9.0.0" - level-errors "^2.0.0" - -encoding@^0.1.12: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - -end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -endent@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/endent/-/endent-2.1.0.tgz#5aaba698fb569e5e18e69e1ff7a28ff35373cd88" - integrity sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w== - dependencies: - dedent "^0.7.0" - fast-json-parse "^1.0.3" - objectorarray "^1.0.5" - -enhanced-resolve@^4.0.0, enhanced-resolve@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" - integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - -enhanced-resolve@^5.8.0: - version "5.8.2" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz#15ddc779345cbb73e97c611cd00c01c1e7bf4d8b" - integrity sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -env-paths@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" - integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== - -envinfo@7.8.1, envinfo@^7.7.3, envinfo@^7.7.4: - version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" - integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== - -err-code@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" - integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== - -errno@^0.1.3, errno@~0.1.1, errno@~0.1.7: - version "0.1.8" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - dependencies: - prr "~1.0.1" - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.17.0-next.0, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: - version "1.18.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0" - integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.2" - is-callable "^1.2.3" - is-negative-zero "^2.0.1" - is-regex "^1.1.3" - is-string "^1.0.6" - object-inspect "^1.10.3" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - -es-get-iterator@^1.0.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" - integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.0" - has-symbols "^1.0.1" - is-arguments "^1.1.0" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.5" - isarray "^2.0.5" - -es-module-lexer@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.7.1.tgz#c2c8e0f46f2df06274cdaf0dd3f3b33e0a0b267d" - integrity sha512-MgtWFl5No+4S3TmhDmCz2ObFGm6lEpTnzbQi+Dd+pw4mlTIZTmM2iAs5gRlmx5zS9luzobCSBSI90JM/1/JgOw== - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.53" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es5-shim@^4.5.13: - version "4.5.15" - resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.5.15.tgz#6a26869b261854a3b045273f5583c52d390217fe" - integrity sha512-FYpuxEjMeDvU4rulKqFdukQyZSTpzhg4ScQHrAosrlVpR6GFyaw14f74yn2+4BugniIS0Frpg7TvwZocU4ZMTw== - -es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-promise@~4.2.8: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-shim@^0.35.5: - version "0.35.6" - resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.6.tgz#d10578301a83af2de58b9eadb7c2c9945f7388a0" - integrity sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA== - -es6-symbol@^3.1.1, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - -es6-templates@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/es6-templates/-/es6-templates-0.2.3.tgz#5cb9ac9fb1ded6eb1239342b81d792bbb4078ee4" - integrity sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ= - dependencies: - recast "~0.11.12" - through "~2.3.6" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-goat@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" - integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -escodegen@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" - integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -eslint-config-prettier@~6.15.0: - version "6.15.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" - integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw== - dependencies: - get-stdin "^6.0.0" - -eslint-plugin-jest@~24.1.3: - version "24.1.10" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.10.tgz#a332c5e517a67f093454293605b1fff365eb8b88" - integrity sha512-ZM9RvLMJZiUVuT4hkGavovA3KwbH5K6F8glnCnX8k5KBsUu2tS1muKAf4nuZpGTokKqMYs7j1HyLcbbOouDVsA== - dependencies: - "@typescript-eslint/experimental-utils" "^4.0.1" - -eslint-plugin-prettier@~3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2" - integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-plugin-react@~7.21.5: - version "7.21.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz#50b21a412b9574bfe05b21db176e8b7b3b15bff3" - integrity sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g== - dependencies: - array-includes "^3.1.1" - array.prototype.flatmap "^1.2.3" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.4.1 || ^3.0.0" - object.entries "^1.1.2" - object.fromentries "^2.0.2" - object.values "^1.1.1" - prop-types "^15.7.2" - resolve "^1.18.1" - string.prototype.matchall "^4.0.2" - -eslint-scope@5.1.1, eslint-scope@^5.0.0, eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-utils@^2.0.0, eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint@~7.14.0: - version "7.14.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.14.0.tgz#2d2cac1d28174c510a97b377f122a5507958e344" - integrity sha512-5YubdnPXrlrYAFCKybPuHIAH++PINe1pmKNc5wQRB9HSbqIK1ywAnntE3Wwua4giKu0bjligf1gLF6qxMGOYRA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@eslint/eslintrc" "^0.2.1" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.0" - esquery "^1.2.0" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.19" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.3.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esprima@~3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= - -esquery@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.1.0, esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -estree-to-babel@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/estree-to-babel/-/estree-to-babel-3.2.1.tgz#82e78315275c3ca74475fdc8ac1a5103c8a75bf5" - integrity sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg== - dependencies: - "@babel/traverse" "^7.1.6" - "@babel/types" "^7.2.0" - c8 "^7.6.0" - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -eventemitter3@^4.0.0, eventemitter3@^4.0.4: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -events@^3.0.0, events@^3.2.0, events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -exec-sh@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" - integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== - dependencies: - merge "^1.2.0" - -exec-sh@^0.3.2: - version "0.3.6" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" - integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - 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" - -execa@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== - 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" - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - 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" - -expect@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" - integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== - 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" - -express-rate-limit@5.5.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-5.5.1.tgz#110c23f6a65dfa96ab468eda95e71697bc6987a2" - integrity sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg== - -express@4.18.2: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.1" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.5.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.2.0" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.11.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -express@^4.16.3, express@^4.17.0: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" - integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== - dependencies: - type "^2.0.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^2.0.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - 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" - -extsprintf@1.3.0, extsprintf@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -fast-deep-equal@^3.1.1, fast-deep-equal@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-glob@^2.0.2: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - -fast-glob@^3.0.3, fast-glob@^3.1.1, fast-glob@^3.2.4: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-parse@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fast-json-parse/-/fast-json-parse-1.0.3.tgz#43e5c61ee4efa9265633046b770fb682a7577c4d" - integrity sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw== - -fast-json-patch@^3.0.0-1: - version "3.0.0-1" - resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-3.0.0-1.tgz#4c68f2e7acfbab6d29d1719c44be51899c93dabb" - integrity sha512-6pdFb07cknxvPzCeLsFHStEy+MysPJPgZQ9LbQ/2O67unQF93SNqfdSqnPPl71YMHX+AD8gbl7iuoGFzHEdDuw== - -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fast-redact@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.0.1.tgz#d6015b971e933d03529b01333ba7f22c29961e92" - integrity sha512-kYpn4Y/valC9MdrISg47tZOpYBNoTXKgT9GYXFpHN/jYFs+lFkPoisY+LcBODdKVMY96ATzvzsWv+ES/4Kmufw== - -fast-safe-stringify@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - -fastest-levenshtein@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" - integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== - -fastparse@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - -fastq@^1.6.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.1.tgz#5d8175aae17db61947f8b162cfc7f63264d22807" - integrity sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw== - dependencies: - reusify "^1.0.4" - -fault@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" - integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== - dependencies: - format "^0.2.0" - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - dependencies: - bser "2.1.1" - -figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -file-loader@^6.0.0, file-loader@~6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.0.0.tgz#97bbfaab7a2460c07bcbd72d3a6922407f67649f" - integrity sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ== - dependencies: - loader-utils "^2.0.0" - schema-utils "^2.6.5" - -file-system-cache@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-1.0.5.tgz#84259b36a2bbb8d3d6eb1021d3132ffe64cfff4f" - integrity sha1-hCWbNqK7uNPW6xAh0xMv/mTP/08= - dependencies: - bluebird "^3.3.5" - fs-extra "^0.30.0" - ramda "^0.21.0" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -filelist@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b" - integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ== - dependencies: - minimatch "^3.0.4" - -filesize@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.0.1.tgz#f850b509909c7c86f7e450ea19006c31c2ed3d2f" - integrity sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg== - -filesize@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" - integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -filter-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" - integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= - -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-cache-dir@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" - integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-root@^1.0.0, find-root@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - -find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - -follow-redirects@^1.0.0: - version "1.14.4" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" - integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -foreground-child@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" - integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^3.0.2" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -fork-ts-checker-webpack-plugin@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz#a1642c0d3e65f50c2cc1742e9c0a80f441f86b19" - integrity sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ== - dependencies: - babel-code-frame "^6.22.0" - chalk "^2.4.1" - chokidar "^3.3.0" - micromatch "^3.1.10" - minimatch "^3.0.4" - semver "^5.6.0" - tapable "^1.0.0" - worker-rpc "^0.1.0" - -fork-ts-checker-webpack-plugin@^4.1.4: - version "4.1.6" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5" - integrity sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw== - dependencies: - "@babel/code-frame" "^7.5.5" - chalk "^2.4.1" - micromatch "^3.1.10" - minimatch "^3.0.4" - semver "^5.6.0" - tapable "^1.0.0" - worker-rpc "^0.1.0" - -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -format@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" - integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -free-style@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/free-style/-/free-style-3.1.0.tgz#4e2996029534e6b1731611d843437b9e2f473f08" - integrity sha512-vJujYSIyT30iDoaoeigNAxX4yB1RUrh+N2ZMhIElMr3BvCuGXOw7XNJMEEJkDUeamK2Rnb/IKFGKRKlTWIGRWA== - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - integrity sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - -fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - -fs-minipass@^2.0.0, fs-minipass@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -fsevents@^2.1.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -function.prototype.name@^1.1.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.4.tgz#e4ea839b9d3672ae99d0efd9f38d9191c5eaac83" - integrity sha512-iqy1pIotY/RmhdFZygSSlW0wko2yxkSCKqsuv4pr8QESohpYyG/Z7B/XXvPRKTJS//960rgguE5mSRUsDdaJrQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - functions-have-names "^1.2.2" - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -functions-have-names@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.2.tgz#98d93991c39da9361f8e50b337c4f6e41f120e21" - integrity sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA== - -fuse.js@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.6.1.tgz#7de85fdd6e1b3377c23ce010892656385fd9b10c" - integrity sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw== - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-pkg-repo@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.1.2.tgz#c4ffd60015cf091be666a0212753fc158f01a4c0" - integrity sha512-/FjamZL9cBYllEbReZkxF2IMh80d8TJoC4e3bmLNif8ibHw95aj0N/tzqK0kZz9eU/3w3dL6lF4fnnX/sDdW3A== - dependencies: - "@hutson/parse-repository-url" "^3.0.0" - hosted-git-info "^4.0.0" - meow "^7.0.0" - through2 "^2.0.0" - -get-port@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - -get-stream@^4.0.0, get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.0.0, get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -git-hooks-list@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-1.0.3.tgz#be5baaf78203ce342f2f844a9d2b03dba1b45156" - integrity sha512-Y7wLWcrLUXwk2noSka166byGCvhMtDRpgHdzCno1UQv/n/Hegp++a2xBWJL1lJarnKD3SWaljD+0z1ztqxuKyQ== - -git-raw-commits@^2.0.8: - version "2.0.10" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" - integrity sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ== - dependencies: - dargs "^7.0.0" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - -git-remote-origin-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" - integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8= - dependencies: - gitconfiglocal "^1.0.0" - pify "^2.3.0" - -git-semver-tags@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" - integrity sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA== - dependencies: - meow "^8.0.0" - semver "^6.0.0" - -git-up@^4.0.0: - version "4.0.5" - resolved "https://registry.yarnpkg.com/git-up/-/git-up-4.0.5.tgz#e7bb70981a37ea2fb8fe049669800a1f9a01d759" - integrity sha512-YUvVDg/vX3d0syBsk/CKUTib0srcQME0JyHkL5BaYdwLsiCslPWmDSi8PUMo9pXYjrryMcmsCoCgsTpSCJEQaA== - dependencies: - is-ssh "^1.3.0" - parse-url "^6.0.0" - -git-url-parse@^11.4.4: - version "11.5.0" - resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-11.5.0.tgz#acaaf65239cb1536185b19165a24bbc754b3f764" - integrity sha512-TZYSMDeM37r71Lqg1mbnMlOqlHd7BSij9qN7XwTkRqSAYFMihGLGhfHwgqQob3GUhEneKnV4nskN9rbQw2KGxA== - dependencies: - git-up "^4.0.0" - -gitconfiglocal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" - integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s= - dependencies: - ini "^1.3.2" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= - dependencies: - is-glob "^2.0.0" - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-parent@^5.0.0, glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-promise@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-3.4.0.tgz#b6b8f084504216f702dc2ce8c9bc9ac8866fdb20" - integrity sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw== - dependencies: - "@types/glob" "*" - -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - -glob@^6.0.1: - version "6.0.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" - integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7, glob@~7.1.6: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - 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" - -global-dirs@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" - integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== - dependencies: - ini "1.3.7" - -global-modules@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - -global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - -global@^4.3.2, global@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -globalthis@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.2.tgz#2a235d34f4d8036219f7e34929b5de9e18166b8b" - integrity sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ== - dependencies: - define-properties "^1.1.3" - -globby@10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.0.tgz#abfcd0630037ae174a88590132c2f6804e291072" - integrity sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw== - dependencies: - "@types/glob" "^7.1.1" - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.0.3" - glob "^7.1.3" - ignore "^5.1.1" - merge2 "^1.2.3" - slash "^3.0.0" - -globby@8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" - integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w== - dependencies: - array-union "^1.0.1" - dir-glob "2.0.0" - fast-glob "^2.0.2" - glob "^7.1.2" - ignore "^3.3.5" - pify "^3.0.0" - slash "^1.0.0" - -globby@^11.0.1, globby@^11.0.2: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -good-listener@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" - integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= - dependencies: - delegate "^3.1.2" - -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== - -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= - -gud@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" - integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== - -gzip-size@5.1.1, gzip-size@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" - integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== - dependencies: - duplexer "^0.1.1" - pify "^4.0.1" - -handlebars@4.7.7, handlebars@^4.5.3, handlebars@^4.7.6, handlebars@^4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.0, har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== - -harmony-reflect@^1.4.6: - version "1.6.2" - resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.2.tgz#31ecbd32e648a34d030d86adb67d4d47547fe710" - integrity sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g== - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has-unicode@^2.0.0, has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has-yarn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" - integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hast-util-parse-selector@^2.0.0: - version "2.2.5" - resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" - integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== - -hastscript@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.2.tgz#bde2c2e56d04c62dd24e8c5df288d050a355fb8a" - integrity sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ== - dependencies: - comma-separated-tokens "^1.0.0" - hast-util-parse-selector "^2.0.0" - property-information "^5.0.0" - space-separated-tokens "^1.0.0" - -he@1.2.x, he@^1.1.0, he@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -highlight.js@~9.15.0, highlight.js@~9.15.1: - version "9.15.10" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2" - integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoist-non-react-statics@^3.3.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -hoopy@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" - integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== - -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - -hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" - integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg== - dependencies: - lru-cache "^6.0.0" - -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - -html-entities@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" - integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -html-loader@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-0.5.5.tgz#6356dbeb0c49756d8ebd5ca327f16ff06ab5faea" - integrity sha512-7hIW7YinOYUpo//kSYcPB6dCKoceKLmOwjEMmhIobHuWGDVl0Nwe4l68mdG/Ru0wcUxQjVMEoZpkalZ/SE7zog== - dependencies: - es6-templates "^0.2.3" - fastparse "^1.1.1" - html-minifier "^3.5.8" - loader-utils "^1.1.0" - object-assign "^4.1.1" - -html-loader@~1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-1.3.2.tgz#5a72ebba420d337083497c9aba7866c9e1aee340" - integrity sha512-DEkUwSd0sijK5PF3kRWspYi56XP7bTNkyg5YWSzBdjaSDmvCufep5c4Vpb3PBf6lUL0YPtLwBfy9fL0t5hBAGA== - dependencies: - html-minifier-terser "^5.1.1" - htmlparser2 "^4.1.0" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -html-minifier-terser@^5.0.1, html-minifier-terser@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" - integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== - dependencies: - camel-case "^4.1.1" - clean-css "^4.2.3" - commander "^4.1.1" - he "^1.2.0" - param-case "^3.0.3" - relateurl "^0.2.7" - terser "^4.6.3" - -html-minifier@^3.5.8: - version "3.5.21" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" - integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== - dependencies: - camel-case "3.0.x" - clean-css "4.2.x" - commander "2.17.x" - he "1.2.x" - param-case "2.1.x" - relateurl "0.2.x" - uglify-js "3.4.x" - -html-webpack-plugin@^4.2.1: - version "4.5.2" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz#76fc83fa1a0f12dd5f7da0404a54e2699666bc12" - integrity sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A== - dependencies: - "@types/html-minifier-terser" "^5.0.0" - "@types/tapable" "^1.0.5" - "@types/webpack" "^4.41.8" - html-minifier-terser "^5.0.1" - loader-utils "^1.2.3" - lodash "^4.17.20" - pretty-error "^2.1.1" - tapable "^1.1.3" - util.promisify "1.0.0" - -html-webpack-plugin@^5.0.0-beta.6: - version "5.3.2" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.3.2.tgz#7b04bf80b1f6fe84a6d3f66c8b79d64739321b08" - integrity sha512-HvB33boVNCz2lTyBsSiMffsJ+m0YLIQ+pskblXgN9fnjS1BgEcuAfdInfXfGrkdXV406k9FiDi86eVCDBgJOyQ== - dependencies: - "@types/html-minifier-terser" "^5.0.0" - html-minifier-terser "^5.0.1" - lodash "^4.17.21" - pretty-error "^3.0.4" - tapable "^2.0.0" - -htmlparser2@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" - integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q== - dependencies: - domelementtype "^2.0.1" - domhandler "^3.0.0" - domutils "^2.0.0" - entities "^2.0.0" - -htmlparser2@^6.0.0, htmlparser2@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" - integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.0.0" - domutils "^2.5.2" - entities "^2.0.0" - -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== - -http-errors@1.7.2, http-errors@~1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -http-link-header@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-0.8.0.tgz#a22b41a0c9b1e2d8fac1bf1b697c6bd532d5f5e4" - integrity sha1-oitBoMmx4tj6wb8baXxr1TLV9eQ= - -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -http-proxy@^1.18.0: - version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-server@^13.0.0: - version "13.0.2" - resolved "https://registry.yarnpkg.com/http-server/-/http-server-13.0.2.tgz#36f8a8ae0e1b78e7bf30a4dfb01ae89b904904ef" - integrity sha512-R8kvPT7qp11AMJWLZsRShvm6heIXdlR/+tL5oAWNG/86A/X+IAFX6q0F9SA2G+dR5aH/759+9PLH0V34Q6j4rg== - dependencies: - basic-auth "^1.0.3" - colors "^1.4.0" - corser "^2.0.1" - he "^1.1.0" - http-proxy "^1.18.0" - mime "^1.6.0" - minimist "^1.2.5" - opener "^1.5.1" - portfinder "^1.0.25" - secure-compare "3.0.1" - union "~0.5.0" - url-join "^2.0.5" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -http-status-codes@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.2.0.tgz#bb2efe63d941dfc2be18e15f703da525169622be" - integrity sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng== - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -https-proxy-agent@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= - dependencies: - ms "^2.0.0" - -iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -icss-utils@^4.0.0, icss-utils@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" - integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== - dependencies: - postcss "^7.0.14" - -icss-utils@^5.0.0, icss-utils@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== - -identity-obj-proxy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14" - integrity sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ= - dependencies: - harmony-reflect "^1.4.6" - -ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - -ignore-walk@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" - integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== - dependencies: - minimatch "^3.0.4" - -ignore@^3.3.5: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.1, ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== - -image-ssim@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/image-ssim/-/image-ssim-0.2.0.tgz#83b42c7a2e6e4b85505477fe6917f5dbc56420e5" - integrity sha1-g7Qsei5uS4VQVHf+aRf128VkIOU= - -immediate@^3.2.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" - integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== - -immer@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" - integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg== - -import-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" - integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= - dependencies: - import-from "^2.1.0" - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - integrity sha1-M1238qev/VOqpHHUuAId7ja387E= - dependencies: - resolve-from "^3.0.0" - -import-lazy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" - integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= - -import-local@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" - integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -infer-owner@^1.0.3, infer-owner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -ini@1.3.7, ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" - integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== - -init-package-json@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.4.tgz#9f9f66cd5934e6d5f645150e15013d384d0b90d2" - integrity sha512-gUACSdZYka+VvnF90TsQorC+1joAVWNI724vBNj3RD0LLMeDss2IuzaeiQs0T4YzKs76BPHtrp/z3sn2p+KDTw== - dependencies: - glob "^7.1.1" - npm-package-arg "^8.1.2" - promzard "^0.3.0" - read "~1.0.1" - read-package-json "^4.0.0" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" - -inquirer@7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703" - integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ== - dependencies: - ansi-escapes "^4.2.1" - chalk "^2.4.2" - cli-cursor "^3.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.15" - mute-stream "0.0.8" - run-async "^2.2.0" - rxjs "^6.5.3" - string-width "^4.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -inquirer@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -inquirer@^7.0.0, inquirer@^7.1.0, inquirer@^7.3.3: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -internmap@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" - integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== - -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - -interpret@^2.0.0, interpret@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" - integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== - -intl-messageformat-parser@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.8.1.tgz#0eb14c5618333be4c95c409457b66c8c33ddcc01" - integrity sha512-IMSCKVf0USrM/959vj3xac7s8f87sc+80Y/ipBzdKy4ifBv5Gsj2tZ41EAaURVg01QU71fYr77uA8Meh6kELbg== - -intl-messageformat@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-4.4.0.tgz#aa196a4d04b573f4090bc417f982d81de4f74fad" - integrity sha512-z+Bj2rS3LZSYU4+sNitdHrwnBhr0wO80ZJSW8EzKDBowwUe3Q/UsvgCGjrwa+HPzoGCLEb9HAjfJgo4j2Sac8w== - dependencies: - intl-messageformat-parser "^1.8.1" - -intl-pluralrules@^1.0.3: - version "1.2.2" - resolved "https://registry.yarnpkg.com/intl-pluralrules/-/intl-pluralrules-1.2.2.tgz#2b73542a9502a8a3a742cdd917f3d969fb5482fe" - integrity sha512-SBdlNCJAhTA0I0uHg2dn7I+c6BCvSVk6zJ/01ozjwJK7BvKms9RH3w3Sd/Ag24KffZ/Yx6KJRCKAc7eE8TZLNg== - -intl@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde" - integrity sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94= - -invariant@^2.2.3, invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - -ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== - -is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - -is-arguments@^1.0.4, is-arguments@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" - integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== - dependencies: - call-bind "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-bigint@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" - integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" - integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng== - dependencies: - call-bind "^1.0.2" - -is-buffer@^1.1.5, is-buffer@~1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-callable@^1.1.4, is-callable@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" - integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-core-module@^2.2.0, is-core-module@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" - integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== - dependencies: - has "^1.0.3" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5" - integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A== - -is-decimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-dom@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.1.0.tgz#af1fced292742443bb59ca3f76ab5e80907b4e8a" - integrity sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ== - dependencies: - is-object "^1.0.1" - is-window "^1.0.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-function@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-glob@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= - dependencies: - is-extglob "^1.0.0" - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== - -is-installed-globally@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" - integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== - dependencies: - global-dirs "^2.0.1" - is-path-inside "^3.0.1" - -is-lambda@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" - integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= - -is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-npm@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" - integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== - -is-number-object@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" - integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw== - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" - integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== - -is-path-inside@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-plain-obj@2.1.0, is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - -is-promise@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - -is-regex@^1.0.4, is-regex@^1.1.2, is-regex@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" - integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== - dependencies: - call-bind "^1.0.2" - has-symbols "^1.0.2" - -is-root@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" - integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== - -is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== - -is-ssh@^1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.3.tgz#7f133285ccd7f2c2c7fc897b771b53d95a2b2c7e" - integrity sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ== - dependencies: - protocols "^1.1.0" - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== - -is-string@^1.0.5, is-string@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" - integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-text-path@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= - dependencies: - text-extensions "^1.0.0" - -is-typedarray@^1.0.0, is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-window@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-window/-/is-window-1.0.2.tgz#2c896ca53db97de45d3c33133a65d8c9f563480d" - integrity sha1-LIlspT25feRdPDMTOmXYyfVjSA0= - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - -is-wsl@^2.1.1, is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -is-yarn-global@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" - integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isobject@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" - integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== - -isomorphic.js@^0.2.4: - version "0.2.5" - resolved "https://registry.yarnpkg.com/isomorphic.js/-/isomorphic.js-0.2.5.tgz#13eecf36f2dba53e85d355e11bf9d4208c6f7f88" - integrity sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw== - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== - -istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -iterate-iterator@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.1.tgz#1693a768c1ddd79c969051459453f082fe82e9f6" - integrity sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw== - -iterate-value@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-value/-/iterate-value-1.0.2.tgz#935115bd37d006a52046535ebc8d07e9c9337f57" - integrity sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ== - dependencies: - es-get-iterator "^1.0.2" - iterate-iterator "^1.0.1" - -jake@^10.6.1: - version "10.8.2" - resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" - integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== - dependencies: - async "0.9.x" - chalk "^2.4.2" - filelist "^1.0.1" - minimatch "^3.0.4" - -jest-changed-files@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" - integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== - dependencies: - "@jest/types" "^26.6.2" - execa "^4.0.0" - throat "^5.0.0" - -jest-cli@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" - integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== - 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" - -jest-config@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" - integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== - 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" - -jest-diff@^26.0.0, jest-diff@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== - dependencies: - chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-docblock@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" - integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== - dependencies: - detect-newline "^3.0.0" - -jest-each@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" - integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== - 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" - -jest-environment-jsdom@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" - integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== - 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" - -jest-environment-node@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" - integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== - 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" - -jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" - integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== - -jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" - integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== - 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" - optionalDependencies: - fsevents "^2.1.2" - -jest-jasmine2@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" - integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== - 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" - -jest-junit@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-11.1.0.tgz#79cd53948e44d62b2b30fa23ea0d7a899d2c8d7a" - integrity sha512-c2LFOyKY7+ZxL5zSu+WHmHfsJ2wqbOpeYJ4Uu26yMhFxny2J2NQj6AVS7M+Eaxji9Q/oIDDK5tQy0DGzDp9xOw== - dependencies: - mkdirp "^1.0.4" - strip-ansi "^5.2.0" - uuid "^3.3.3" - xml "^1.0.1" - -jest-leak-detector@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" - integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== - dependencies: - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-matcher-utils@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" - integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== - dependencies: - chalk "^4.0.0" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-message-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" - integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== - 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" - -jest-mock@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" - integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - -jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== - -jest-raw-loader@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz#ce9f56d54650f157c4a7d16d224ba5d613bcd626" - integrity sha1-zp9W1UZQ8VfEp9FtIkul1hO81iY= - -jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== - -jest-resolve-dependencies@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" - integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== - dependencies: - "@jest/types" "^26.6.2" - jest-regex-util "^26.0.0" - jest-snapshot "^26.6.2" - -jest-resolve@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" - integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== - 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" - -jest-retries@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/jest-retries/-/jest-retries-1.0.1.tgz#b60eac2c6f6ee7033fbc9a3cb6f3016a63b82822" - integrity sha512-tR9tCXs9+Vqw/2toQEOg+CpzOwUqReppcZH2550EnuEhw4F8TR+NbICPUJexegjN9xnuF4ABSGPgzCgAFZI0Ng== - -jest-runner@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" - integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== - 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" - -jest-runtime@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" - integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== - 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" - -jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" - integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" - -jest-snapshot@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" - integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== - 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" - -jest-summary-reporter@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/jest-summary-reporter/-/jest-summary-reporter-0.0.2.tgz#53b9997b56f343a0dd9af24199c68d371e01f534" - integrity sha512-rZ3ThO57l+ZJCxF74cXIGQU3cV9I7bSBe1ElBp0taE3x2JghgD69bNCKt0LvpVQX5azTRHG7LmcjIpwriVnTng== - dependencies: - chalk "^2.4.1" - -jest-util@^26.1.0, jest-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" - integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== - 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" - -jest-validate@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" - integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== - 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" - -jest-watcher@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" - integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== - 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" - -jest-worker@^26.2.1, jest-worker@^26.5.0, jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - -jest-worker@^27.0.2: - version "27.0.6" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.6.tgz#a5fdb1e14ad34eb228cfe162d9f729cdbfa28aed" - integrity sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^26.4.2: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" - integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== - dependencies: - "@jest/core" "^26.6.3" - import-local "^3.0.2" - jest-cli "^26.6.3" - -jpeg-js@^0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" - integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== - -js-library-detector@^5.7.0: - version "5.9.0" - resolved "https://registry.yarnpkg.com/js-library-detector/-/js-library-detector-5.9.0.tgz#ad0add7f4991424326895b273e774876555d0e1b" - integrity sha512-0wYHRVJv8uVsylJhfQQaH2vOBYGehyZyJbtaHuchoTP3Mb6hqYvrA0hoMQ1ZhARLHzHJMbMc/nCr4D3pTNSCgw== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - -js-yaml@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@^16.4.0: - version "16.6.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.6.0.tgz#f79b3786682065492a3da6a60a4695da983805ac" - integrity sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg== - dependencies: - 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.5" - xml-name-validator "^3.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-compare@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/json-schema-compare/-/json-schema-compare-0.2.2.tgz#dd601508335a90c7f4cfadb6b2e397225c908e56" - integrity sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ== - dependencies: - lodash "^4.17.4" - -json-schema-merge-allof@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/json-schema-merge-allof/-/json-schema-merge-allof-0.6.0.tgz#64d48820fec26b228db837475ce3338936bf59a5" - integrity sha512-LEw4VMQVRceOPLuGRWcxW5orTTiR9ZAtqTAe4rQUjNADTeR81bezBVFa0MqIwp0YmHIM1KkhSjZM7o+IQhaPbQ== - dependencies: - compute-lcm "^1.1.0" - json-schema-compare "^0.2.2" - lodash "^4.17.4" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-schema@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-pretty-compact@^3.0.0, json-stringify-pretty-compact@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz#f71ef9d82ef16483a407869556588e91b681d9ab" - integrity sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA== - -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json-to-html@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/json-to-html/-/json-to-html-0.1.2.tgz#7a095ae4a34b33534aad0970ca4b7417b2c11ee3" - integrity sha1-egla5KNLM1NKrQlwykt0F7LBHuM= - -json2html@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/json2html/-/json2html-0.0.8.tgz#6c64ee08259744fd28a49fb97d7746b29ae0501d" - integrity sha1-bGTuCCWXRP0opJ+5fXdGsprgUB0= - dependencies: - underscore ">=1.3.1" - -json5@2.x, json5@^2.1.1, json5@^2.1.2, json5@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonld@^1.5.0: - version "1.8.1" - resolved "https://registry.yarnpkg.com/jsonld/-/jsonld-1.8.1.tgz#55ea541b22b8af5a5d6a5e32328e3f2678148882" - integrity sha512-f0rusl5v8aPKS3jApT5fhYsdTC/JpyK1PoJ+ZtYYtZXoyb1J0Z///mJqLwrfL/g4NueFSqPymDYIi1CcSk7b8Q== - dependencies: - canonicalize "^1.0.1" - rdf-canonize "^1.0.2" - request "^2.88.0" - semver "^5.6.0" - xmldom "0.1.19" - -jsonlint-mod@^1.7.5: - version "1.7.6" - resolved "https://registry.yarnpkg.com/jsonlint-mod/-/jsonlint-mod-1.7.6.tgz#6f1c4c51fdb5c2002489a0665e3e19a316743319" - integrity sha512-oGuk6E1ehmIpw0w9ttgb2KsDQQgGXBzZczREW8OfxEm9eCQYL9/LCexSnh++0z3AiYGcXpBgqDSx9AAgzl/Bvg== - dependencies: - JSV "^4.0.2" - chalk "^2.4.2" - underscore "^1.9.1" - -jsonparse@^1.2.0, jsonparse@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= - -jsonpointer@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.1.0.tgz#501fb89986a2389765ba09e6053299ceb4f2c2cc" - integrity sha512-CXcRvMyTlnR53xMcKnuMzfCA5i/nfblTnnr74CZb6C4vG39eu6w51t7nKmU5MfLfbTgGItliNyjO/ciNPDqClg== - -jsonwebtoken@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" - integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== - dependencies: - jws "^3.2.2" - lodash "^4.17.21" - ms "^2.1.1" - semver "^7.3.8" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -"jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" - integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== - dependencies: - array-includes "^3.1.2" - object.assign "^4.1.2" - -jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" - integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - -jws@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" - integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== - dependencies: - jwa "^1.4.1" - safe-buffer "^5.0.1" - -keygrip@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" - integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ== - dependencies: - tsscmp "1.0.6" - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= - optionalDependencies: - graceful-fs "^4.1.9" - -kleur@4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" - integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -latest-version@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" - integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== - dependencies: - package-json "^6.3.0" - -lazy-universal-dotenv@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz#a6c8938414bca426ab8c9463940da451a911db38" - integrity sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ== - dependencies: - "@babel/runtime" "^7.5.0" - app-root-dir "^1.0.2" - core-js "^3.0.4" - dotenv "^8.0.0" - dotenv-expand "^5.1.0" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - -lerna@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-4.0.0.tgz#b139d685d50ea0ca1be87713a7c2f44a5b678e9e" - integrity sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg== - dependencies: - "@lerna/add" "4.0.0" - "@lerna/bootstrap" "4.0.0" - "@lerna/changed" "4.0.0" - "@lerna/clean" "4.0.0" - "@lerna/cli" "4.0.0" - "@lerna/create" "4.0.0" - "@lerna/diff" "4.0.0" - "@lerna/exec" "4.0.0" - "@lerna/import" "4.0.0" - "@lerna/info" "4.0.0" - "@lerna/init" "4.0.0" - "@lerna/link" "4.0.0" - "@lerna/list" "4.0.0" - "@lerna/publish" "4.0.0" - "@lerna/run" "4.0.0" - "@lerna/version" "4.0.0" - import-local "^3.0.2" - npmlog "^4.1.2" - -level-codec@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" - integrity sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ== - dependencies: - buffer "^5.6.0" - -level-concat-iterator@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" - integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== - -level-errors@^2.0.0, level-errors@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" - integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== - dependencies: - errno "~0.1.1" - -level-iterator-stream@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" - integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== - dependencies: - inherits "^2.0.4" - readable-stream "^3.4.0" - xtend "^4.0.2" - -level-js@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/level-js/-/level-js-5.0.2.tgz#5e280b8f93abd9ef3a305b13faf0b5397c969b55" - integrity sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg== - dependencies: - abstract-leveldown "~6.2.3" - buffer "^5.5.0" - inherits "^2.0.3" - ltgt "^2.1.2" - -level-packager@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" - integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== - dependencies: - encoding-down "^6.3.0" - levelup "^4.3.2" - -level-supports@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" - integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== - dependencies: - xtend "^4.0.2" - -level@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/level/-/level-6.0.1.tgz#dc34c5edb81846a6de5079eac15706334b0d7cd6" - integrity sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw== - dependencies: - level-js "^5.0.0" - level-packager "^5.1.0" - leveldown "^5.4.0" - -leveldown@^5.4.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.6.0.tgz#16ba937bb2991c6094e13ac5a6898ee66d3eee98" - integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ== - dependencies: - abstract-leveldown "~6.2.1" - napi-macros "~2.0.0" - node-gyp-build "~4.1.0" - -levelup@^4.3.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" - integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== - dependencies: - deferred-leveldown "~5.3.0" - level-errors "~2.0.0" - level-iterator-stream "~4.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lib0@^0.2.31, lib0@^0.2.42, lib0@^0.2.49, lib0@^0.2.52: - version "0.2.63" - resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.63.tgz#9fe7c26686fbb4b1578bc0d8ee1d308ad6115d4e" - integrity sha512-JhUd/JXR4rnWsSP1zup904ACbVFcdRieWoIGwGAtHww4zms0gNyi8EM30Rfftnk+6A10qQMSufjLM0/ncq06xw== - dependencies: - isomorphic.js "^0.2.4" - -libnpmaccess@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" - integrity sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ== - dependencies: - aproba "^2.0.0" - minipass "^3.1.1" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" - -libnpmpublish@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.2.tgz#be77e8bf5956131bcb45e3caa6b96a842dec0794" - integrity sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw== - dependencies: - normalize-package-data "^3.0.2" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" - semver "^7.1.3" - ssri "^8.0.1" - -license-webpack-plugin@^2.3.14: - version "2.3.19" - resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.19.tgz#f02720b2b0bcd9ae27fb63f0bd908d9ac9335d6c" - integrity sha512-z/izhwFRYHs1sCrDgrTUsNJpd+Xsd06OcFWSwHz/TiZygm5ucweVZi1Hu14Rf6tOj/XAl1Ebyc7GW6ZyyINyWA== - dependencies: - "@types/webpack-sources" "^0.1.5" - webpack-sources "^1.2.0" - -lighthouse-logger@^1.0.0, lighthouse-logger@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz#b76d56935e9c137e86a04741f6bb9b2776e886ca" - integrity sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw== - dependencies: - debug "^2.6.8" - marky "^1.2.0" - -lighthouse@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/lighthouse/-/lighthouse-6.3.0.tgz#7a8af15435ed7f175b6c7d30821a6a3fa9094163" - integrity sha512-ZiU6e6S5haKfHPIxCrmMXg9ZIyt4XrzOdbSIMPvKSCfFttUYYm4jdtA3nO4hox7lm+/eo7dE6JBSO0QAfA9bBg== - dependencies: - axe-core "3.5.5" - chrome-launcher "^0.13.3" - configstore "^5.0.1" - cssstyle "1.2.1" - details-element-polyfill "^2.4.0" - http-link-header "^0.8.0" - inquirer "^3.3.0" - intl "^1.2.5" - intl-messageformat "^4.4.0" - intl-pluralrules "^1.0.3" - jpeg-js "^0.4.1" - js-library-detector "^5.7.0" - jsonld "^1.5.0" - jsonlint-mod "^1.7.5" - lighthouse-logger "^1.2.0" - lodash.isequal "^4.5.0" - lodash.set "^4.3.2" - lookup-closest-locale "6.0.4" - metaviewport-parser "0.2.0" - open "^6.4.0" - parse-cache-control "1.0.1" - ps-list "^7.2.0" - raven "^2.2.1" - rimraf "^2.6.1" - robots-parser "^2.0.1" - semver "^5.3.0" - speedline-core "^1.4.3" - third-party-web "^0.12.1" - update-notifier "^4.1.0" - ws "3.3.2" - yargs "3.32.0" - yargs-parser "^18.1.3" - -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -load-json-file@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" - integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== - dependencies: - graceful-fs "^4.1.15" - parse-json "^5.0.0" - strip-bom "^4.0.0" - type-fest "^0.6.0" - -loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== - -loader-runner@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" - integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== - -loader-utils@1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" - integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== - dependencies: - big.js "^5.2.2" - emojis-list "^2.0.0" - json5 "^1.0.1" - -loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.0.3, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - -loader-utils@^2.0.0, loader-utils@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" - integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lockfile@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" - integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== - dependencies: - signal-exit "^3.0.2" - -lodash-es@^4.17.15, lodash-es@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - -lodash.curry@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" - integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA= - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - -lodash.escape@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" - integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg= - -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= - -lodash.ismatch@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" - integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= - -lodash.set@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" - integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= - -lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - -lodash@4, lodash@4.17.21, lodash@4.x, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.7.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - -loglevelnext@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" - integrity sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A== - dependencies: - es6-symbol "^3.1.1" - object.assign "^4.1.0" - -lookup-closest-locale@6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/lookup-closest-locale/-/lookup-closest-locale-6.0.4.tgz#1279fed7546a601647bbc980f64423ee990a8590" - integrity sha512-bWoFbSGe6f1GvMGzj17LrwMX4FhDXDwZyH04ySVCPbtOJADcSRguZNKewoJ3Ful/MOxD/wRHvFPadk/kYZUbuQ== - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lowdb@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-1.0.0.tgz#5243be6b22786ccce30e50c9a33eac36b20c8064" - integrity sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ== - dependencies: - graceful-fs "^4.1.3" - is-promise "^2.1.0" - lodash "4" - pify "^3.0.0" - steno "^0.4.1" - -lower-case@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" - integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= - -lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" - integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== - dependencies: - tslib "^2.0.3" - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lowlight@1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.12.1.tgz#014acf8dd73a370e02ff1cc61debcde3bb1681eb" - integrity sha512-OqaVxMGIESnawn+TU/QMV5BJLbUghUfjDWPAtFqDYDmDtr4FnB+op8xM+pR7nKlauHNUHXGt0VgWatFB8voS5w== - dependencies: - fault "^1.0.2" - highlight.js "~9.15.0" - -lru-cache@7.14.1: - version "7.14.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea" - integrity sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -ltgt@^2.1.2: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" - integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU= - -lunr-mutable-indexes@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/lunr-mutable-indexes/-/lunr-mutable-indexes-2.3.2.tgz#864253489735d598c5140f3fb75c0a5c8be2e98c" - integrity sha512-Han6cdWAPPFM7C2AigS2Ofl3XjAT0yVMrUixodJEpyg71zCtZ2yzXc3s+suc/OaNt4ca6WJBEzVnEIjxCTwFMw== - dependencies: - lunr ">= 2.3.0 < 2.4.0" - -"lunr@>= 2.3.0 < 2.4.0", lunr@^2.3.9: - version "2.3.9" - resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" - integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== - -make-dir@^2.0.0, make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@1.x: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -make-fetch-happen@^8.0.9: - version "8.0.14" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" - integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.0.5" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - promise-retry "^2.0.1" - socks-proxy-agent "^5.0.0" - ssri "^8.0.0" - -make-fetch-happen@^9.0.1: - version "9.1.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" - integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.2.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.2" - promise-retry "^2.0.1" - socks-proxy-agent "^6.0.0" - ssri "^8.0.0" - -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= - dependencies: - tmpl "1.0.x" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - -map-obj@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" - integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== - -map-or-similar@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/map-or-similar/-/map-or-similar-1.5.0.tgz#6de2653174adfb5d9edc33c69d3e92a1b76faf08" - integrity sha1-beJlMXSt+12e3DPGnT6Sobdvrwg= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -markdown-loader-jest@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/markdown-loader-jest/-/markdown-loader-jest-0.1.1.tgz#7de45f7e6c8644805bd02ca126dfb54a55cf8255" - integrity sha512-osdgJgjxP/9C+vcIkTxU5p91C3+IkD2yY+SvG4GcFOOfAK0mixqepDSkNdMIsCf10KK9DfHjPUslnzKLH1tktg== - dependencies: - html-loader "^0.5.1" - markdown-loader "^2.0.1" - -markdown-loader@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/markdown-loader/-/markdown-loader-2.0.2.tgz#1cdcf11307658cd611046d7db34c2fe80542af7c" - integrity sha512-v/ej7DflZbb6t//3Yu9vg0T+sun+Q9EoqggifeyABKfvFROqPwwwpv+hd1NKT2QxTRg6VCFk10IIJcMI13yCoQ== - dependencies: - loader-utils "^1.1.0" - marked "^0.3.9" - -markdown-to-jsx@^6.11.4: - version "6.11.4" - resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-6.11.4.tgz#b4528b1ab668aef7fe61c1535c27e837819392c5" - integrity sha512-3lRCD5Sh+tfA52iGgfs/XZiw33f7fFX9Bn55aNnVNUd2GzLDkOWyKYYD8Yju2B1Vn+feiEdgJs8T6Tg0xNokPw== - dependencies: - prop-types "^15.6.2" - unquote "^1.1.0" - -marked@^0.3.9: - version "0.3.19" - resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790" - integrity sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg== - -marked@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/marked/-/marked-2.1.3.tgz#bd017cef6431724fd4b27e0657f5ceb14bff3753" - integrity sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA== - -marked@^4.0.17: - version "4.0.17" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.17.tgz#1186193d85bb7882159cdcfc57d1dfccaffb3fe9" - integrity sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA== - -marky@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.2.tgz#4456765b4de307a13d263a69b0c79bf226e68323" - integrity sha512-k1dB2HNeaNyORco8ulVEhctyEGkKHb2YWAhDsxeFlW2nROIirsctBYzKwwS3Vza+sKTS1zO4Z+n9/+9WbGLIxQ== - -material-colors@^1.2.1: - version "1.2.6" - resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" - integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -md5@^2.2.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" - integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== - dependencies: - charenc "0.0.2" - crypt "0.0.2" - is-buffer "~1.1.6" - -mdn-data@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== - -mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -memoizerific@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a" - integrity sha1-fIekZGREwy11Q4VwkF8tvRsagFo= - dependencies: - map-or-similar "^1.5.0" - -memory-fs@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -meow@^7.0.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/meow/-/meow-7.1.1.tgz#7c01595e3d337fcb0ec4e8eed1666ea95903d306" - integrity sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^2.5.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.13.1" - yargs-parser "^18.1.3" - -meow@^8.0.0: - version "8.1.2" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" - integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.2.3, merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -merge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" - integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== - -metaviewport-parser@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/metaviewport-parser/-/metaviewport-parser-0.2.0.tgz#535c3ce1ccf6223a5025fddc6a1c36505f7e7db1" - integrity sha1-U1w84cz2IjpQJf3cahw2UF9+fbE= - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -microevent.ts@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" - integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== - -micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - 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" - -micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.48.0, "mime-db@>= 1.43.0 < 2": - version "1.48.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d" - integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ== - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.31" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b" - integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg== - dependencies: - mime-db "1.48.0" - -mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0, mime@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - -mime@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" - integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== - -mime@^2.4.4: - version "2.5.2" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" - integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -mimic-response@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" - integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= - dependencies: - dom-walk "^0.1.0" - -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - -mini-css-extract-plugin@~1.3.2: - version "1.3.9" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.9.tgz#47a32132b0fd97a119acd530e8421e8f6ab16d5e" - integrity sha512-Ac4s+xhVbqlyhXS5J/Vh/QXUz3ycXlCqoCPpg0vdfhsIBH9eg/It/9L1r1XhSCH737M1lqcWnMuWL13zcygn5A== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - webpack-sources "^1.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist-options@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" - -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.0: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" - integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== - dependencies: - minipass "^3.0.0" - -minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" - integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== - dependencies: - minipass "^3.1.0" - minipass-sized "^1.0.3" - minizlib "^2.0.0" - optionalDependencies: - encoding "^0.1.12" - -minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" - integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== - dependencies: - minipass "^3.0.0" - -minipass-json-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" - integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== - dependencies: - jsonparse "^1.3.1" - minipass "^3.0.0" - -minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" - integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== - dependencies: - minipass "^3.0.0" - -minipass-sized@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" - integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== - dependencies: - minipass "^3.0.0" - -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" - integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== - dependencies: - yallist "^4.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - -minizlib@^2.0.0, minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp-infer-owner@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" - integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== - dependencies: - chownr "^2.0.0" - infer-owner "^1.0.4" - mkdirp "^1.0.3" - -mkdirp@1.0.4, mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -modify-values@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" - integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== - -moment@^2.24.0: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -ms@2.1.2, ms@^2.0.0, ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multimatch@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" - integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== - dependencies: - "@types/minimatch" "^3.0.3" - array-differ "^3.0.0" - array-union "^2.1.0" - arrify "^2.0.1" - minimatch "^3.0.4" - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -mute-stream@0.0.8, mute-stream@~0.0.4: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -mv@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" - integrity sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI= - dependencies: - mkdirp "~0.5.1" - ncp "~2.0.0" - rimraf "~2.4.0" - -nan@^2.12.1: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== - -nan@^2.17.0: - version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== - -nanoclone@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" - integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA== - -nanoid@^3.1.23, nanoid@^3.1.30: - version "3.1.30" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" - integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - 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" - -napi-macros@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" - integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -ncp@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" - integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= - -negotiator@0.6.2, negotiator@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1, neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -next-tick@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -no-case@^2.2.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" - integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== - dependencies: - lower-case "^1.1.1" - -no-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" - integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== - dependencies: - lower-case "^2.0.2" - tslib "^2.0.3" - -node-dir@^0.1.10: - version "0.1.17" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" - integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= - dependencies: - minimatch "^3.0.2" - -node-fetch@^2.6.0, node-fetch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - -node-fetch@cjs: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-forge@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" - integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== - -node-gyp-build@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" - integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== - -node-gyp@^5.0.2: - version "5.1.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" - integrity sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.2" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.1.2" - request "^2.88.0" - rimraf "^2.6.3" - semver "^5.7.1" - tar "^4.4.12" - which "^1.3.1" - -node-gyp@^7.1.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" - integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.3" - nopt "^5.0.0" - npmlog "^4.1.2" - request "^2.88.2" - rimraf "^3.0.2" - semver "^7.3.2" - tar "^6.0.2" - which "^2.0.2" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - -node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - -node-notifier@^8.0.0: - version "8.0.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" - integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== - 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-releases@^1.1.52, node-releases@^1.1.71: - version "1.1.73" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" - integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg== - -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - -normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" - integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== - dependencies: - hosted-git-info "^4.0.1" - is-core-module "^2.5.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - -normalize-url@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== - -normalize.css@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3" - integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg== - -npm-bundled@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" - integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== - dependencies: - npm-normalize-package-bin "^1.0.1" - -npm-install-checks@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" - integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== - dependencies: - semver "^7.1.1" - -npm-lifecycle@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz#9882d3642b8c82c815782a12e6a1bfeed0026309" - integrity sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g== - dependencies: - byline "^5.0.0" - graceful-fs "^4.1.15" - node-gyp "^5.0.2" - resolve-from "^4.0.0" - slide "^1.1.6" - uid-number "0.0.6" - umask "^1.1.0" - which "^1.3.1" - -npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.2: - version "8.1.5" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" - integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== - dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" - validate-npm-package-name "^3.0.0" - -npm-packlist@^2.1.4: - version "2.2.2" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" - integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg== - dependencies: - glob "^7.1.6" - ignore-walk "^3.0.3" - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" - -npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" - integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== - dependencies: - npm-install-checks "^4.0.0" - npm-normalize-package-bin "^1.0.1" - npm-package-arg "^8.1.2" - semver "^7.3.4" - -npm-registry-fetch@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" - integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== - dependencies: - make-fetch-happen "^9.0.1" - minipass "^3.1.3" - minipass-fetch "^1.3.0" - minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" - -npm-registry-fetch@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" - integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== - dependencies: - "@npmcli/ci-detect" "^1.0.0" - lru-cache "^6.0.0" - make-fetch-happen "^8.0.9" - minipass "^3.1.3" - minipass-fetch "^1.3.0" - minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -npm-run-path@^4.0.0, npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -npmlog@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -nth-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - -nth-check@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125" - integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q== - dependencies: - boolbase "^1.0.0" - -null-loader@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/null-loader/-/null-loader-4.0.1.tgz#8e63bd3a2dd3c64236a4679428632edd0a6dbc6a" - integrity sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -nwsapi@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.10.3, object-inspect@^1.9.0: - version "1.10.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" - integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== - -object-is@^1.0.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0, object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.entries@^1.1.0, object.entries@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd" - integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.2" - -"object.fromentries@^2.0.0 || ^1.0.0", object.fromentries@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8" - integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has "^1.0.3" - -object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" - integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -object.values@^1.1.0, object.values@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" - integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.2" - -objectorarray@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5" - integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg== - -on-exit-leak-free@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" - integrity sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg== - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -onigasm@^2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/onigasm/-/onigasm-2.2.5.tgz#cc4d2a79a0fa0b64caec1f4c7ea367585a676892" - integrity sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA== - dependencies: - lru-cache "^5.1.1" - -open@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" - integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== - dependencies: - is-wsl "^1.1.0" - -open@^7.0.2, open@^7.0.3: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - -opener@^1.5.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" - integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== - -optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - 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" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= - dependencies: - lcid "^1.0.0" - -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -os@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/os/-/os-0.1.1.tgz#208845e89e193ad4d971474b93947736a56d13f3" - integrity sha1-IIhF6J4ZOtTZcUdLk5R3NqVtE/M= - -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -overlayscrollbars@^1.10.2: - version "1.13.1" - resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz#0b840a88737f43a946b9d87875a2f9e421d0338a" - integrity sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ== - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - -p-each-series@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" - integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2, p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-map-series@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" - integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== - -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -p-pipe@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" - integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== - -p-queue@^6.6.2: - version "6.6.2" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" - integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== - dependencies: - eventemitter3 "^4.0.4" - p-timeout "^3.2.0" - -p-reduce@^2.0.0, p-reduce@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" - integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== - -p-timeout@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" - integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -p-waterfall@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" - integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== - dependencies: - p-reduce "^2.0.0" - -package-json@^6.3.0, package-json@^6.5.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" - integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== - dependencies: - got "^9.6.0" - registry-auth-token "^4.0.0" - registry-url "^5.0.0" - semver "^6.2.0" - -pacote@^11.2.6: - version "11.3.5" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" - integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== - dependencies: - "@npmcli/git" "^2.1.0" - "@npmcli/installed-package-contents" "^1.0.6" - "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^1.8.2" - cacache "^15.0.5" - chownr "^2.0.0" - fs-minipass "^2.1.0" - infer-owner "^1.0.4" - minipass "^3.1.3" - mkdirp "^1.0.3" - npm-package-arg "^8.0.1" - npm-packlist "^2.1.4" - npm-pick-manifest "^6.0.0" - npm-registry-fetch "^11.0.0" - promise-retry "^2.0.1" - read-package-json-fast "^2.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.1.0" - -pako@~1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - -param-case@2.1.x: - version "2.1.1" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" - integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= - dependencies: - no-case "^2.2.0" - -param-case@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" - integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-cache-control@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" - integrity sha1-juqz5U+laSD+Fro493+iGqzC104= - -parse-entities@^1.1.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" - integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - 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" - -parse-path@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf" - integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA== - dependencies: - is-ssh "^1.3.0" - protocols "^1.4.0" - qs "^6.9.4" - query-string "^6.13.8" - -parse-srcset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" - integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE= - -parse-url@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.0.tgz#f5dd262a7de9ec00914939220410b66cff09107d" - integrity sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw== - dependencies: - is-ssh "^1.3.0" - normalize-url "^6.1.0" - parse-path "^4.0.0" - protocols "^1.4.0" - -parse5@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascal-case@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" - integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - -path-browserify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -path@~0.12.7: - version "0.12.7" - resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" - integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8= - dependencies: - process "^0.11.1" - util "^0.10.3" - -pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== - -pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" - integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== - -pino-abstract-transport@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz#cc0d6955fffcadb91b7b49ef220a6cc111d48bb3" - integrity sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA== - dependencies: - readable-stream "^4.0.0" - split2 "^4.0.0" - -pino-abstract-transport@v0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz#4b54348d8f73713bfd14e3dc44228739aa13d9c0" - integrity sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ== - dependencies: - duplexify "^4.1.2" - split2 "^4.0.0" - -pino-std-serializers@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz#1791ccd2539c091ae49ce9993205e2cd5dbba1e2" - integrity sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q== - -pino@7.11.0: - version "7.11.0" - resolved "https://registry.yarnpkg.com/pino/-/pino-7.11.0.tgz#0f0ea5c4683dc91388081d44bff10c83125066f6" - integrity sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg== - dependencies: - atomic-sleep "^1.0.0" - fast-redact "^3.0.0" - on-exit-leak-free "^0.2.0" - pino-abstract-transport v0.5.0 - pino-std-serializers "^4.0.0" - process-warning "^1.0.0" - quick-format-unescaped "^4.0.3" - real-require "^0.1.0" - safe-stable-stringify "^2.1.0" - sonic-boom "^2.2.1" - thread-stream "^0.15.1" - -pirates@^4.0.0, pirates@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pkg-dir@^4.1.0, pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -pkg-up@3.1.0, pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - -pkginfo@0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" - integrity sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8= - -playwright-core@1.22.1: - version "1.22.1" - resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.22.1.tgz#59ddf903546171fdfd9c3dc189630c883619667c" - integrity sha512-H+ZUVYnceWNXrRf3oxTEKAr81QzFsCKu5Fp//fEjQvqgKkfA1iX3E9DBrPJpPNOrgVzcE+IqeI0fDmYJe6Ynnw== - -pnp-webpack-plugin@1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" - integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg== - dependencies: - ts-pnp "^1.1.6" - -polished@^3.4.4: - version "3.7.2" - resolved "https://registry.yarnpkg.com/polished/-/polished-3.7.2.tgz#ec5ddc17a7d322a574d5e10ddd2a6f01d3e767d1" - integrity sha512-pQKtpZGmsZrW8UUpQMAnR7s3ppHeMQVNyMDKtUyKwuvDmklzcEyM5Kllb3JyE/sE/x7arDmyd35i+4vp99H6sQ== - dependencies: - "@babel/runtime" "^7.12.5" - -popper.js@^1.14.4, popper.js@^1.14.7, popper.js@^1.16.1: - version "1.16.1" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - -portfinder@^1.0.25: - version "1.0.28" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" - integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== - dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.5" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-flexbugs-fixes@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz#9218a65249f30897deab1033aced8578562a6690" - integrity sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ== - dependencies: - postcss "^7.0.26" - -postcss-load-config@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a" - integrity sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw== - dependencies: - cosmiconfig "^5.0.0" - import-cwd "^2.0.0" - -postcss-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" - integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== - dependencies: - loader-utils "^1.1.0" - postcss "^7.0.0" - postcss-load-config "^2.0.0" - schema-utils "^1.0.0" - -postcss-modules-extract-imports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" - integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== - dependencies: - postcss "^7.0.5" - -postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== - -postcss-modules-local-by-default@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" - 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" - -postcss-modules-local-by-default@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" - integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== - dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" - integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - -postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== - dependencies: - postcss-selector-parser "^6.0.4" - -postcss-modules-values@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" - integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== - dependencies: - icss-utils "^4.0.0" - postcss "^7.0.6" - -postcss-modules-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" - integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== - dependencies: - icss-utils "^5.0.0" - -postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: - version "6.0.6" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" - integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== - -postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.36" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.36.tgz#056f8cffa939662a8f5905950c07d5285644dfcb" - integrity sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^8.2.15, postcss@^8.3.11: - version "8.3.11" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858" - integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA== - dependencies: - nanoid "^3.1.30" - picocolors "^1.0.0" - source-map-js "^0.6.2" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.2.tgz#3050700dae2e4c8b67c4c3f666cdb8af405e1ce5" - integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg== - -pretty-error@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" - integrity sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw== - dependencies: - lodash "^4.17.20" - renderkid "^2.0.4" - -pretty-error@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-3.0.4.tgz#94b1d54f76c1ed95b9c604b9de2194838e5b574e" - integrity sha512-ytLFLfv1So4AO1UkoBF6GXQgJRaKbiSiGFICaOPNwQ3CMvBvXpLRubeQWyPGnsbV/t9ml9qto6IeCsho0aEvwQ== - dependencies: - lodash "^4.17.20" - renderkid "^2.0.6" - -pretty-format@^26.0.0, pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - -pretty-hrtime@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" - integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= - -prismjs@^1.8.4, prismjs@~1.17.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.17.1.tgz#e669fcbd4cdd873c35102881c33b14d0d68519be" - integrity sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q== - optionalDependencies: - clipboard "^2.0.0" - -private@~0.1.5: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process-warning@1.0.0, process-warning@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" - integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== - -process@^0.11.1, process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -progress@^2.0.0, progress@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= - -promise-retry@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" - integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== - dependencies: - err-code "^2.0.2" - retry "^0.12.0" - -promise.allsettled@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.4.tgz#65e71f2a604082ed69c548b68603294090ee6803" - integrity sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag== - dependencies: - array.prototype.map "^1.0.3" - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - get-intrinsic "^1.0.2" - iterate-value "^1.0.2" - -promise.prototype.finally@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067" - integrity sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.0" - function-bind "^1.1.1" - -prompts@^2.0.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" - integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -promzard@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" - integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= - dependencies: - read "1" - -prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" - -property-expr@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" - integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== - -property-information@^5.0.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" - integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== - dependencies: - xtend "^4.0.0" - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= - -protocols@^1.1.0, protocols@^1.4.0: - version "1.4.8" - resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" - integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== - -proxy-addr@~2.0.5, proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - -ps-list@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-7.2.0.tgz#3d110e1de8249a4b178c9b1cf2a215d1e4e42fc0" - integrity sha512-v4Bl6I3f2kJfr5o80ShABNHAokIgY+wFDTQfE+X3zWYgSGQOCBeYptLZUpoOALBqO5EawmDN/tjTldJesd0ujQ== - -psl@^1.1.24, psl@^1.1.28, psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.2.4, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -pupa@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" - integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== - dependencies: - escape-goat "^2.0.0" - -q@^1.1.2, q@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -qs@^6.4.0, qs@^6.6.0, qs@^6.9.4: - version "6.10.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" - integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== - dependencies: - side-channel "^1.0.4" - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -query-string@^6.13.8: - version "6.14.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" - integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw== - dependencies: - decode-uri-component "^0.2.0" - filter-obj "^1.1.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0, querystring@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -quick-format-unescaped@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz#6d6b66b8207aa2b35eef12be1421bb24c428f652" - integrity sha512-MaL/oqh02mhEo5m5J2rwsVL23Iw2PEaGVHgT2vFt8AAsr0lfvQA5dpXo9TPu0rz7tSBdUPgkbam0j/fj5ZM8yg== - -quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - -ramda@^0.21.0: - version "0.21.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" - integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raven@^2.2.1: - version "2.6.4" - resolved "https://registry.yarnpkg.com/raven/-/raven-2.6.4.tgz#458d4a380c8fbb59e0150c655625aaf60c167ea3" - integrity sha512-6PQdfC4+DQSFncowthLf+B6Hr0JpPsFBgTVYTAOq7tCmx/kR4SXbeawtPch20+3QfUcQDoJBLjWW1ybvZ4kXTw== - dependencies: - cookie "0.3.1" - md5 "^2.2.1" - stack-trace "0.0.10" - timed-out "4.0.1" - uuid "3.3.2" - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -raw-loader@^4.0.1, raw-loader@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6" - integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -rc@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -rdf-canonize@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/rdf-canonize/-/rdf-canonize-1.2.0.tgz#9872b2cc6ed92a9969e834f9f042addaf0d4f7f9" - integrity sha512-MQdcRDz4+82nUrEb3hNQangBDpmep15uMmnWclGi/1KS0bNVc8oHpoNI0PFLHZsvwgwRzH31bO1JAScqUAstvw== - dependencies: - node-forge "^0.10.0" - semver "^6.3.0" - -react-base16-styling@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.8.0.tgz#6251b814b4e09efab3284ae1ecdd490f2c4111eb" - integrity sha512-ElvciPaL4xpWh7ISX7ugkNS/dvoh7DpVMp4t93ngnEsS2LkMd8Gu+cDDOLis2rj4889CNK662UdjOfv3wvZg9w== - dependencies: - "@types/base16" "^1.0.2" - "@types/lodash.curry" "^4.1.6" - base16 "^1.0.0" - color "^3.1.2" - csstype "^3.0.2" - lodash.curry "^4.1.1" - -react-color@^2.17.0: - version "2.19.3" - resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d" - integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA== - dependencies: - "@icons/material" "^0.2.4" - lodash "^4.17.15" - lodash-es "^4.17.15" - material-colors "^1.2.1" - prop-types "^15.5.10" - reactcss "^1.2.0" - tinycolor2 "^1.4.1" - -react-dev-utils@^10.0.0: - version "10.2.1" - resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.1.tgz#f6de325ae25fa4d546d09df4bb1befdc6dd19c19" - integrity sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ== - dependencies: - "@babel/code-frame" "7.8.3" - address "1.1.2" - browserslist "4.10.0" - chalk "2.4.2" - cross-spawn "7.0.1" - detect-port-alt "1.1.6" - escape-string-regexp "2.0.0" - filesize "6.0.1" - find-up "4.1.0" - fork-ts-checker-webpack-plugin "3.1.1" - global-modules "2.0.0" - globby "8.0.2" - gzip-size "5.1.1" - immer "1.10.0" - inquirer "7.0.4" - is-root "2.1.0" - loader-utils "1.2.3" - open "^7.0.2" - pkg-up "3.1.0" - react-error-overlay "^6.0.7" - recursive-readdir "2.2.2" - shell-quote "1.7.2" - strip-ansi "6.0.0" - text-table "0.2.0" - -react-docgen-typescript-loader@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/react-docgen-typescript-loader/-/react-docgen-typescript-loader-3.7.2.tgz#45cb2305652c0602767242a8700ad1ebd66bbbbd" - integrity sha512-fNzUayyUGzSyoOl7E89VaPKJk9dpvdSgyXg81cUkwy0u+NBvkzQG3FC5WBIlXda0k/iaxS+PWi+OC+tUiGxzPA== - dependencies: - "@webpack-contrib/schema-utils" "^1.0.0-beta.0" - loader-utils "^1.2.3" - react-docgen-typescript "^1.15.0" - -react-docgen-typescript-plugin@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-0.5.2.tgz#2b294d75ef3145c36303da82be5d447cb67dc0dc" - integrity sha512-NQfWyWLmzUnedkiN2nPDb6Nkm68ik6fqbC3UvgjqYSeZsbKijXUA4bmV6aU7qICOXdop9PevPdjEgJuAN0nNVQ== - dependencies: - debug "^4.1.1" - endent "^2.0.1" - micromatch "^4.0.2" - react-docgen-typescript "^1.20.1" - react-docgen-typescript-loader "^3.7.2" - tslib "^2.0.0" - -react-docgen-typescript@^1.15.0, react-docgen-typescript@^1.20.1: - version "1.22.0" - resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-1.22.0.tgz#00232c8e8e47f4437cac133b879b3e9437284bee" - integrity sha512-MPLbF8vzRwAG3GcjdL+OHQlhgtWsLTXs+7uJiHfEeT3Ur7IsZaNYqRTLQ9sj2nB6M6jylcPCeCmH7qbszJmecg== - -react-docgen@^5.0.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-5.4.0.tgz#2cd7236720ec2769252ef0421f23250b39a153a1" - integrity sha512-JBjVQ9cahmNlfjMGxWUxJg919xBBKAoy3hgDgKERbR+BcF4ANpDuzWAScC7j27hZfd8sJNmMPOLWo9+vB/XJEQ== - dependencies: - "@babel/core" "^7.7.5" - "@babel/generator" "^7.12.11" - "@babel/runtime" "^7.7.6" - ast-types "^0.14.2" - commander "^2.19.0" - doctrine "^3.0.0" - estree-to-babel "^3.1.0" - neo-async "^2.6.1" - node-dir "^0.1.10" - strip-indent "^3.0.0" - -react-dom@^16.8.3: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" - integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" - -react-dom@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - -react-draggable@^4.0.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.3.tgz#0727f2cae5813e36b0e4962bf11b2f9ef2b406f3" - integrity sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w== - dependencies: - classnames "^2.2.5" - prop-types "^15.6.0" - -react-error-overlay@^6.0.7: - version "6.0.9" - resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" - integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== - -react-fast-compare@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" - integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== - -react-helmet-async@^1.0.2: - version "1.0.9" - resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.0.9.tgz#5b9ed2059de6b4aab47f769532f9fbcbce16c5ca" - integrity sha512-N+iUlo9WR3/u9qGMmP4jiYfaD6pe9IvDTapZLFJz2D3xlTlCM1Bzy4Ab3g72Nbajo/0ZyW+W9hdz8Hbe4l97pQ== - dependencies: - "@babel/runtime" "^7.12.5" - invariant "^2.2.4" - prop-types "^15.7.2" - react-fast-compare "^3.2.0" - shallowequal "^1.1.0" - -react-highlighter@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/react-highlighter/-/react-highlighter-0.4.3.tgz#e32c84d053259c30ca72c615aa759036d0d23048" - integrity sha512-dwItRaGRHBceuzZd5NXeroapdmZ2JCAWZ3AdwdthRlSkdtPCY18DWrd6mPmiMCfSB6lgVwwCPQl4unZzG5sXXw== - dependencies: - blacklist "^1.1.4" - create-react-class "^15.6.2" - escape-string-regexp "^1.0.5" - prop-types "^15.6.0" - -react-hotkeys@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/react-hotkeys/-/react-hotkeys-2.0.0.tgz#a7719c7340cbba888b0e9184f806a9ec0ac2c53f" - integrity sha512-3n3OU8vLX/pfcJrR3xJ1zlww6KS1kEJt0Whxc4FiGV+MJrQ1mYSYI3qS/11d2MJDFm8IhOXMTFQirfu6AVOF6Q== - dependencies: - prop-types "^15.6.1" - -react-inspector@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-5.1.1.tgz#58476c78fde05d5055646ed8ec02030af42953c8" - integrity sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg== - dependencies: - "@babel/runtime" "^7.0.0" - is-dom "^1.0.0" - prop-types "^15.0.0" - -react-is@^16.7.0, react-is@^16.8.1, react-is@^16.9.0: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -react-json-tree@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/react-json-tree/-/react-json-tree-0.15.0.tgz#16a5bbed761f711d1656de6c62818d40ddb09442" - integrity sha512-/bEFXZBfLFiep6ReuzatR8mz9G7sRmejElRDgcAuqY0Jsx7llouax2DM03rlQifrUJgmvTGmPA+olyWYyGagqA== - dependencies: - "@types/prop-types" "^15.7.3" - prop-types "^15.7.2" - react-base16-styling "^0.8.0" - -react-lifecycles-compat@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - -react-paginate@^6.3.2: - version "6.5.0" - resolved "https://registry.yarnpkg.com/react-paginate/-/react-paginate-6.5.0.tgz#b9baf53627b115cfd688afa048776aa45bffda19" - integrity sha512-H7xSi9jyiJzgfaj+2nNhQcjZfwzJ/Mxb64V2RiyDctjZyCWojwsaGwMqhLBpQ58iAuMVtBMRQ7ECqMcUKG9QSQ== - dependencies: - prop-types "^15.6.1" - -react-popper-tooltip@^2.11.0: - version "2.11.1" - resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-2.11.1.tgz#3c4bdfd8bc10d1c2b9a162e859bab8958f5b2644" - integrity sha512-04A2f24GhyyMicKvg/koIOQ5BzlrRbKiAgP6L+Pdj1MVX3yJ1NeZ8+EidndQsbejFT55oW1b++wg2Z8KlAyhfQ== - dependencies: - "@babel/runtime" "^7.9.2" - react-popper "^1.3.7" - -react-popper@^1.3.7: - version "1.3.11" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.11.tgz#a2cc3f0a67b75b66cfa62d2c409f9dd1fcc71ffd" - integrity sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg== - dependencies: - "@babel/runtime" "^7.1.2" - "@hypnosphi/create-react-context" "^0.3.1" - deep-equal "^1.1.1" - popper.js "^1.14.4" - prop-types "^15.6.1" - typed-styles "^0.0.7" - warning "^4.0.2" - -react-sizeme@^2.6.7: - version "2.6.12" - resolved "https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-2.6.12.tgz#ed207be5476f4a85bf364e92042520499455453e" - integrity sha512-tL4sCgfmvapYRZ1FO2VmBmjPVzzqgHA7kI8lSJ6JS6L78jXFNRdOZFpXyK6P1NBZvKPPCZxReNgzZNUajAerZw== - dependencies: - element-resize-detector "^1.2.1" - invariant "^2.2.4" - shallowequal "^1.1.0" - throttle-debounce "^2.1.0" - -react-syntax-highlighter@^12.2.1: - version "12.2.1" - resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-12.2.1.tgz#14d78352da1c1c3f93c6698b70ec7c706b83493e" - integrity sha512-CTsp0ZWijwKRYFg9xhkWD4DSpQqE4vb2NKVMdPAkomnILSmsNBHE0n5GuI5zB+PU3ySVvXvdt9jo+ViD9XibCA== - dependencies: - "@babel/runtime" "^7.3.1" - highlight.js "~9.15.1" - lowlight "1.12.1" - prismjs "^1.8.4" - refractor "^2.4.1" - -react-textarea-autosize@^8.1.1: - version "8.3.3" - resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8" - integrity sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ== - dependencies: - "@babel/runtime" "^7.10.2" - use-composed-ref "^1.0.0" - use-latest "^1.0.0" - -react-toastify@^9.0.8: - version "9.0.8" - resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-9.0.8.tgz#3876c89fc6211a29027b3075010b5ec39ebe4f7e" - integrity sha512-EwM+teWt49HSHx+67qI08yLAW1zAsBxCXLCsUfxHYv1W7/R3ZLhrqKalh7j+kjgPna1h5LQMSMwns4tB4ww2yQ== - dependencies: - clsx "^1.1.1" - -react-transition-group@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d" - integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg== - dependencies: - dom-helpers "^3.4.0" - loose-envify "^1.4.0" - prop-types "^15.6.2" - react-lifecycles-compat "^3.0.4" - -react@^16.8.3: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" - integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - -react@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -reactcss@^1.2.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" - integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A== - dependencies: - lodash "^4.0.1" - -read-cmd-shim@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" - integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== - -read-package-json-fast@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" - integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== - dependencies: - json-parse-even-better-errors "^2.3.0" - npm-normalize-package-bin "^1.0.1" - -read-package-json@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" - integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^2.0.0" - npm-normalize-package-bin "^1.0.0" - -read-package-json@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" - integrity sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^3.0.0" - npm-normalize-package-bin "^1.0.0" - -read-package-json@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-4.0.1.tgz#da88a38c410344fecb7d840d35f27635e848ea54" - integrity sha512-czqCcYfkEl6sIFJVOND/5/Goseu7cVw1rcDUATq6ED0jLGjMm9/HOPmFmEZMvRu9yl272YERaMUcOlvcNU9InQ== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^3.0.0" - npm-normalize-package-bin "^1.0.0" - -read-package-tree@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" - integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== - dependencies: - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - util-promisify "^2.1.0" - -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -read@1, read@~1.0.1: - version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= - dependencies: - mute-stream "~0.0.4" - -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - 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" - -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.3.0.tgz#0914d0c72db03b316c9733bb3461d64a3cc50cba" - integrity sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ== - dependencies: - abort-controller "^3.0.0" - buffer "^6.0.3" - events "^3.3.0" - process "^0.11.10" - -readdir-scoped-modules@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" - integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - graceful-fs "^4.1.2" - once "^1.3.0" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -real-require@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.1.0.tgz#736ac214caa20632847b7ca8c1056a0767df9381" - integrity sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg== - -recast@~0.11.12: - version "0.11.23" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" - integrity sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM= - dependencies: - ast-types "0.9.6" - esprima "~3.1.0" - private "~0.1.5" - source-map "~0.5.0" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= - dependencies: - resolve "^1.1.6" - -rechoir@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca" - integrity sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q== - dependencies: - resolve "^1.9.0" - -recursive-readdir@2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" - integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== - dependencies: - minimatch "3.0.4" - -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" - -refractor@^2.4.1: - version "2.10.1" - resolved "https://registry.yarnpkg.com/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e" - integrity sha512-Xh9o7hQiQlDbxo5/XkOX6H+x/q8rmlmZKr97Ie1Q8ZM32IRRd3B/UxuA/yXDW79DBSXGWxm2yRTbcTVmAciJRw== - dependencies: - hastscript "^5.0.0" - parse-entities "^1.1.2" - prismjs "~1.17.0" - -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: - version "0.13.7" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" - integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== - -regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" - integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== - dependencies: - "@babel/runtime" "^7.8.4" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" - integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -regexpp@^3.0.0, regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -regexpu-core@^4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" - integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== - 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" - -registry-auth-token@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" - integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== - dependencies: - rc "^1.2.8" - -registry-url@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" - integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== - dependencies: - rc "^1.2.8" - -regjsgen@^0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" - integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== - -regjsparser@^0.6.4: - version "0.6.9" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6" - integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ== - dependencies: - jsesc "~0.5.0" - -relateurl@0.2.x, relateurl@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -renderkid@^2.0.4, renderkid@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609" - integrity sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ== - dependencies: - css-select "^4.1.3" - dom-converter "^0.2.0" - htmlparser2 "^6.1.0" - lodash "^4.17.21" - strip-ansi "^3.0.1" - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request@2.88.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== - 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.0" - 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.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -request@^2.88.0, request@^2.88.2: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - 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" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - -resize-observer-polyfill@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" - integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.1.10, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.9.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0, rimraf@^3.0.2, rimraf@~3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rimraf@~2.4.0: - version "2.4.5" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" - integrity sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto= - dependencies: - glob "^6.0.1" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -robots-parser@^2.0.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/robots-parser/-/robots-parser-2.3.0.tgz#d79e86e26e13fa0a806adbc37f4cf1b96aebc8c3" - integrity sha512-RvuCITckrHM9k8DxCCU9rqWpuuKRfVX9iHG751dC3/EdERxp9gJATxYYdYOT3L0T+TAT4+27lENisk/VbHm47A== - -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - -run-async@^2.2.0, run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rw@1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" - integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q= - -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= - -rxjs@^6.4.0, rxjs@^6.5.3, rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -safe-buffer@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== - -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1, safe-buffer@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -safe-stable-stringify@^2.1.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz#ec7b037768098bf65310d1d64370de0dc02353aa" - integrity sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA== - -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - 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" - -sanitize-html@~2.7.3: - version "2.7.3" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.7.3.tgz#166c868444ee4f9fd7352ac8c63fa86c343fc2bd" - integrity sha512-jMaHG29ak4miiJ8wgqA1849iInqORgNv7SLfSw9LtfOhEUQ1C0YHKH73R+hgyufBW9ZFeJrb057k9hjlfBCVlw== - dependencies: - deepmerge "^4.2.2" - escape-string-regexp "^4.0.0" - htmlparser2 "^6.0.0" - is-plain-object "^5.0.0" - parse-srcset "^1.0.2" - postcss "^8.3.11" - -sax@~1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - -scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -schema-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - -schema-utils@^2.6.5, schema-utils@^2.6.6, schema-utils@^2.7.0: - version "2.7.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" - integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== - dependencies: - "@types/json-schema" "^7.0.5" - ajv "^6.12.4" - ajv-keywords "^3.5.2" - -schema-utils@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.0.tgz#95986eb604f66daadeed56e379bfe7a7f963cdb9" - integrity sha512-tTEaeYkyIhEZ9uWgAjDerWov3T9MgX8dhhy2r0IGeeX4W8ngtGl1++dUve/RUqzuaASSh7shwCDJjEzthxki8w== - dependencies: - "@types/json-schema" "^7.0.7" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -secure-compare@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3" - integrity sha1-8aAymzCLIh+uN7mXTz1XjQypmeM= - -select@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" - integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= - -semver-diff@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" - integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== - dependencies: - semver "^6.3.0" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -semver@7.3.8, semver@^7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" - -semver@7.x, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - -serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== - dependencies: - randombytes "^2.1.0" - -serialize-javascript@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== - dependencies: - randombytes "^2.1.0" - -serve-favicon@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.5.0.tgz#935d240cdfe0f5805307fdfe967d88942a2cbcf0" - integrity sha1-k10kDN/g9YBTB/3+ln2IlCosvPA= - dependencies: - etag "~1.8.1" - fresh "0.5.2" - ms "2.1.1" - parseurl "~1.3.2" - safe-buffer "5.1.1" - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" - -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@1.7.2, shell-quote@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" - integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== - -shelljs@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" - integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - -shiki@^0.9.3: - version "0.9.5" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.9.5.tgz#c8da81a05fbfd1810729c6873901a729a72ec541" - integrity sha512-XFn+rl3wIowDjzdr5DlHoHgQphXefgUTs2bNp/bZu4WF9gTrTLnKwio3f28VjiFG6Jpip7yQn/p4mMj6OrjrtQ== - dependencies: - json5 "^2.2.0" - onigasm "^2.2.5" - vscode-textmate "5.2.0" - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" - integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== - -simple-get@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3" - integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA== - dependencies: - decompress-response "^4.2.0" - once "^1.3.1" - simple-concat "^1.0.0" - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - -simulate-event@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/simulate-event/-/simulate-event-1.4.0.tgz#7f8a404116280bcbfe26347ddbcbffe5bd2be00e" - integrity sha1-f4pAQRYoC8v+JjR928v/5b0r4A4= - dependencies: - xtend "^4.0.1" - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -slide@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - -smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - 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" - -socks-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" - integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== - dependencies: - agent-base "^6.0.2" - debug "4" - socks "^2.3.3" - -socks-proxy-agent@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" - integrity sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg== - dependencies: - agent-base "^6.0.2" - debug "^4.3.1" - socks "^2.6.1" - -socks@^2.3.3, socks@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" - integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== - dependencies: - ip "^1.1.5" - smart-buffer "^4.1.0" - -sonic-boom@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-3.2.1.tgz#972ceab831b5840a08a002fa95a672008bda1c38" - integrity sha512-iITeTHxy3B9FGu8aVdiDXUVAcHMF9Ss0cCsAOo2HfCrmVGT3/DT5oYaeu0M/YKZDlKTvChEyPq0zI9Hf33EX6A== - dependencies: - atomic-sleep "^1.0.0" - -sonic-boom@^2.2.1: - version "2.8.0" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-2.8.0.tgz#c1def62a77425090e6ad7516aad8eb402e047611" - integrity sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg== - dependencies: - atomic-sleep "^1.0.0" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - -sort-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" - integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== - dependencies: - is-plain-obj "^2.0.0" - -sort-object-keys@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45" - integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg== - -sort-package-json@~1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.44.0.tgz#470330be868f8a524a4607b26f2a0233e93d8b6d" - integrity sha512-u9GUZvpavUCXV5SbEqXu9FRbsJrYU6WM10r3zA0gymGPufK5X82MblCLh9GW9l46pXKEZvK+FA3eVTqC4oMp4A== - dependencies: - detect-indent "^6.0.0" - detect-newline "3.1.0" - git-hooks-list "1.0.3" - globby "10.0.0" - is-plain-obj "2.1.0" - sort-object-keys "^1.1.3" - -source-list-map@^2.0.0, source-list-map@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - -source-map-js@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" - integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== - -source-map-loader@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-1.0.2.tgz#b0a6582b2eaa387ede1ecf8061ae0b93c23f9eb0" - integrity sha512-oX8d6ndRjN+tVyjj6PlXSyFPhDdVAPsZA30nD3/II8g4uOv8fCz0DMn5sy8KtVbDfKQxOpGwGJnK3xIW3tauDw== - dependencies: - data-urls "^2.0.0" - iconv-lite "^0.6.2" - loader-utils "^2.0.0" - schema-utils "^2.7.0" - source-map "^0.6.1" - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - 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" - -source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.3, source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -space-separated-tokens@^1.0.0: - version "1.1.5" - resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" - integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f" - integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ== - -speedline-core@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/speedline-core/-/speedline-core-1.4.3.tgz#4d6e7276e2063c2d36a375cb25a523ac73475319" - integrity sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog== - dependencies: - "@types/node" "*" - image-ssim "^0.2.0" - jpeg-js "^0.4.1" - -split-on-first@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" - integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -split2@^3.0.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - -split2@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" - integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== - -split@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - dependencies: - through "2" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - 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" - -ssri@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" - integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== - dependencies: - figgy-pudding "^3.5.1" - -ssri@^8.0.0, ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -stack-trace@0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" - integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= - -stack-utils@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== - dependencies: - escape-string-regexp "^2.0.0" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -steno@^0.4.1: - version "0.4.4" - resolved "https://registry.yarnpkg.com/steno/-/steno-0.4.4.tgz#071105bdfc286e6615c0403c27e9d7b5dcb855cb" - integrity sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs= - dependencies: - graceful-fs "^4.1.3" - -store2@^2.7.1: - version "2.12.0" - resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf" - integrity sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw== - -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - -strict-uri-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2", string-width@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -"string.prototype.matchall@^4.0.0 || ^3.0.1", string.prototype.matchall@^4.0.2: - version "4.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz#59370644e1db7e4c0c045277690cf7b01203c4da" - integrity sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.2" - get-intrinsic "^1.1.1" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" - side-channel "^1.0.4" - -string.prototype.padend@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz#6858ca4f35c5268ebd5e8615e1327d55f59ee311" - integrity sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - -string.prototype.padstart@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.padstart/-/string.prototype.padstart-3.1.2.tgz#f9b9ce66bedd7c06acb40ece6e34c6046e1a019d" - integrity sha512-HDpngIP3pd0DeazrfqzuBrQZa+D2arKWquEHfGt5LzVjd+roLC3cjqVI0X8foaZz5rrrhcu8oJAQamW8on9dqw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string_decoder@^1.0.0, string_decoder@^1.1.1, string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@6.0.0, strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -strong-log-transformer@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" - integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== - dependencies: - duplexer "^0.1.1" - minimist "^1.2.0" - through "^2.3.4" - -style-loader@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" - integrity sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q== - dependencies: - loader-utils "^2.0.0" - schema-utils "^2.7.0" - -style-loader@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" - integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0, supports-color@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-hyperlinks@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" - integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - -svg-parser@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" - integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== - -svg-url-loader@~6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/svg-url-loader/-/svg-url-loader-6.0.0.tgz#b94861d9f6badfb8ca3e7d3ec4655c1bf732ac5d" - integrity sha512-Qr5SCKxyxKcRnvnVrO3iQj9EX/v40UiGEMshgegzV7vpo3yc+HexELOdtWcA3MKjL8IyZZ1zOdcILmDEa/8JJQ== - dependencies: - file-loader "~6.0.0" - loader-utils "~2.0.0" - -svgo-loader@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/svgo-loader/-/svgo-loader-2.2.2.tgz#5f54e3e0d77c36a84c42bcb42e812c4db534bf96" - integrity sha512-UeE/4yZEK96LoYqvxwh8YqCOJCjXwRY9K6YT99vXE+nYhs/W8hAY2hNf5zg/lRsyKshJkR79V+4beV3cbGL40Q== - dependencies: - js-yaml "^3.13.1" - loader-utils "^1.0.3" - -svgo@^1.2.2, svgo@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" - integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.37" - csso "^4.0.2" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -symbol.prototype.description@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/symbol.prototype.description/-/symbol.prototype.description-1.0.4.tgz#c30edd3fe8c040d941cf7dc15842be15adf66855" - integrity sha512-fZkHwJ8ZNRVRzF/+/2OtygyyH06CjC0YZAQRHu9jKKw8RXlJpbizEHvGRUu22Qkg182wJk1ugb5Aovcv3UPrww== - dependencies: - call-bind "^1.0.2" - es-abstract "^1.18.0-next.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.2" - -systeminformation@^5.8.6: - version "5.9.4" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.9.4.tgz#1f0e29e0aa376dec8f69cc517eeefc5cdcda411a" - integrity sha512-FOsiTn0CyJZoj9kIhla11ndsMzbbwwuriul81wpqIBt9IpbxHZ6P/oZCphIFgJrwqjTnme0Qp1HDzIkUD9Xr/g== - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -tapable@^1.0.0, tapable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== - -tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" - integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== - -tar@^4.4.12: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - -tar@^6.0.2, tar@^6.1.0: - version "6.1.11" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" - integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -telejson@^5.0.2: - version "5.3.3" - resolved "https://registry.yarnpkg.com/telejson/-/telejson-5.3.3.tgz#fa8ca84543e336576d8734123876a9f02bf41d2e" - integrity sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA== - dependencies: - "@types/is-function" "^1.0.0" - global "^4.4.0" - is-function "^1.0.2" - is-regex "^1.1.2" - is-symbol "^1.0.3" - isobject "^4.0.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= - -temp-write@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" - integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== - dependencies: - graceful-fs "^4.1.15" - is-stream "^2.0.0" - make-dir "^3.0.0" - temp-dir "^1.0.0" - uuid "^3.3.2" - -term-size@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" - integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== - -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - -terser-webpack-plugin@^1.4.3: - version "1.4.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" - integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - -terser-webpack-plugin@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-3.1.0.tgz#91e6d39571460ed240c0cf69d295bcf30ebf98cb" - integrity sha512-cjdZte66fYkZ65rQ2oJfrdCAkkhJA7YLYk5eGOcGCSGlq0ieZupRdjedSQXYknMPo2IveQL+tPdrxUkERENCFA== - dependencies: - cacache "^15.0.5" - find-cache-dir "^3.3.1" - jest-worker "^26.2.1" - p-limit "^3.0.2" - schema-utils "^2.6.6" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.8.0" - webpack-sources "^1.4.3" - -terser-webpack-plugin@^4.1.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a" - integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ== - dependencies: - cacache "^15.0.5" - find-cache-dir "^3.3.1" - jest-worker "^26.5.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - source-map "^0.6.1" - terser "^5.3.4" - webpack-sources "^1.4.3" - -terser-webpack-plugin@^5.1.3: - version "5.1.4" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz#c369cf8a47aa9922bd0d8a94fe3d3da11a7678a1" - integrity sha512-C2WkFwstHDhVEmsmlCxrXUtVklS+Ir1A7twrYzrDrQQOIMOaVAYykaoo/Aq1K0QRkMoY2hhvDQY1cm4jnIMFwA== - dependencies: - jest-worker "^27.0.2" - p-limit "^3.1.0" - schema-utils "^3.0.0" - serialize-javascript "^6.0.0" - source-map "^0.6.1" - terser "^5.7.0" - -terser@^4.1.2, terser@^4.6.3, terser@^4.8.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -terser@^5.3.4, terser@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784" - integrity sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-encoding@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643" - integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA== - -text-extensions@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" - integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== - -text-table@0.2.0, text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -third-party-web@^0.12.1: - version "0.12.4" - resolved "https://registry.yarnpkg.com/third-party-web/-/third-party-web-0.12.4.tgz#e189d97e6e86c42b470e96b9c46719cd906ccb64" - integrity sha512-SaJdgPjCus/5ftexuCk8wJnYwe/nW9ZNDcWZc/dq90SREN6PvFEUva+kgaPZfT8opLDHvjJVAG9mNVvMnHeVgw== - -thread-stream@^0.15.1: - version "0.15.2" - resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-0.15.2.tgz#fb95ad87d2f1e28f07116eb23d85aba3bc0425f4" - integrity sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA== - dependencies: - real-require "^0.1.0" - -throat@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== - -throttle-debounce@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2" - integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ== - -through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through2@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - -through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@~2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -timed-out@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - -timers-browserify@^2.0.4: - version "2.0.12" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" - integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== - dependencies: - setimmediate "^1.0.4" - -tiny-emitter@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" - integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== - -tinycolor2@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" - integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -tmpl@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -to-string-loader@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/to-string-loader/-/to-string-loader-1.1.6.tgz#230529ccc63dd0ecca052a85e1fb82afe946b0ab" - integrity sha512-VNg62//PS1WfNwrK3n7t6wtK5Vdtx/qeYLLEioW46VMlYUwAYT6wnfB+OwS2FMTCalIHu0tk79D3RXX8ttmZTQ== - dependencies: - loader-utils "^1.0.0" - -toggle-selection@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" - integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -topojson-client@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/topojson-client/-/topojson-client-3.1.0.tgz#22e8b1ed08a2b922feeb4af6f53b6ef09a467b99" - integrity sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw== - dependencies: - commander "2" - -toposort@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" - integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== - -tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.1.2" - -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== - dependencies: - psl "^1.1.24" - punycode "^1.4.1" - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== - -trim-off-newlines@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" - integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= - -tryer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" - integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== - -ts-dedent@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-1.2.0.tgz#6aa2229d837159bb6d635b6b233002423b91e0b0" - integrity sha512-6zSJp23uQI+Txyz5LlXMXAHpUhY4Hi0oluXny0OgIR7g/Cromq4vDBnhtbBdyIV34g0pgwxUvnvg+jLJe4c1NA== - -ts-essentials@^2.0.3: - version "2.0.12" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745" - integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w== - -ts-jest@^26.3.0: - version "26.5.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" - integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - jest-util "^26.1.0" - json5 "2.x" - lodash "4.x" - make-error "1.x" - mkdirp "1.x" - semver "7.x" - yargs-parser "20.x" - -ts-loader@^6.2.1: - version "6.2.2" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.2.tgz#dffa3879b01a1a1e0a4b85e2b8421dc0dfff1c58" - integrity sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ== - dependencies: - chalk "^2.3.0" - enhanced-resolve "^4.0.0" - loader-utils "^1.0.2" - micromatch "^4.0.0" - semver "^6.0.0" - -ts-pnp@^1.1.6: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" - integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== - -tslib@^1.8.1, tslib@^1.9.0, tslib@~1.13.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" - integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== - -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.2.0, tslib@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - -tsscmp@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" - integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== - -tsutils@^3.17.1: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -typanion@^3.8.0: - version "3.12.1" - resolved "https://registry.yarnpkg.com/typanion/-/typanion-3.12.1.tgz#d33deb130aba23ef6f2a3c69e7fb28148dd9089a" - integrity sha512-3SJF/czpzqq6G3lprGFLa6ps12yb1uQ1EmitNnep2fDMNh1aO/Zbq9sWY+3lem0zYb2oHJnQWyabTGUZ+L1ScQ== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" - integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== - -type-fest@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" - integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw== - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.0.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d" - integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw== - -typed-styles@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" - integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -typedoc-default-themes@^0.12.10: - version "0.12.10" - resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz#614c4222fe642657f37693ea62cad4dafeddf843" - integrity sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA== - -typedoc@~0.21.2: - version "0.21.2" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.21.2.tgz#cf5094314d3d63e95a8ef052ceff06a6cafd509d" - integrity sha512-SR1ByJB3USg+jxoxwzMRP07g/0f/cQUE5t7gOh1iTUyjTPyJohu9YSKRlK+MSXXqlhIq+m0jkEHEG5HoY7/Adg== - dependencies: - glob "^7.1.7" - handlebars "^4.7.7" - lodash "^4.17.21" - lunr "^2.3.9" - marked "^2.1.1" - minimatch "^3.0.0" - progress "^2.0.3" - shiki "^0.9.3" - typedoc-default-themes "^0.12.10" - -typescript@~4.1.3: - version "4.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.6.tgz#1becd85d77567c3c741172339e93ce2e69932138" - integrity sha512-pxnwLxeb/Z5SP80JDRzVjh58KsM6jZHRAOtTpS7sXLS4ogXNKC9ANxHHZqLLeVHZN35jCtI4JdmLLbLiC1kBow== - -typestyle@^2.0.4: - version "2.1.0" - resolved "https://registry.yarnpkg.com/typestyle/-/typestyle-2.1.0.tgz#7c5cc567de72cd8bfb686813150b92791aaa7636" - integrity sha512-6uCYPdG4xWLeEcl9O0GtNFnNGhami+irKiLsXSuvWHC/aTS7wdj49WeikWAKN+xHN3b1hm+9v0svwwgSBhCsNA== - dependencies: - csstype "2.6.9" - free-style "3.1.0" - -uglify-js@3.4.x, uglify-js@^3.1.4: - version "3.4.10" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" - integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw== - dependencies: - commander "~2.19.0" - source-map "~0.6.1" - -uid-number@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= - -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== - -umask@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" - integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= - -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -underscore@>=1.3.1, underscore@^1.9.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" - integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== - -unfetch@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" - integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -union@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/union/-/union-0.5.0.tgz#b2c11be84f60538537b846edb9ba266ba0090075" - integrity sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA== - dependencies: - qs "^6.4.0" - -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - -universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== - -universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -unix-crypt-td-js@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz#4912dfad1c8aeb7d20fa0a39e4c31918c1d5d5dd" - integrity sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -unquote@^1.1.0, unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - -upath@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" - integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== - -update-notifier@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" - integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== - dependencies: - boxen "^4.2.0" - chalk "^3.0.0" - configstore "^5.0.1" - has-yarn "^2.1.0" - import-lazy "^2.1.0" - is-ci "^2.0.0" - is-installed-globally "^0.3.1" - is-npm "^4.0.0" - is-yarn-global "^0.3.0" - latest-version "^5.0.0" - pupa "^2.0.1" - semver-diff "^3.1.1" - xdg-basedir "^4.0.0" - -upper-case@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" - integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-join@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" - integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= - -url-loader@^4.0.0, url-loader@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" - integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== - dependencies: - loader-utils "^2.0.0" - mime-types "^2.1.27" - schema-utils "^3.0.0" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -url-parse@~1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" - integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use-composed-ref@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.1.0.tgz#9220e4e94a97b7b02d7d27eaeab0b37034438bbc" - integrity sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg== - dependencies: - ts-essentials "^2.0.3" - -use-isomorphic-layout-effect@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225" - integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ== - -use-latest@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232" - integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw== - dependencies: - use-isomorphic-layout-effect "^1.0.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util-promisify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" - integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= - dependencies: - object.getownpropertydescriptors "^2.0.3" - -util.promisify@1.0.0, util.promisify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - -util@0.10.3, util@^0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - -utila@~0.4: - version "0.4.0" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - -uuid@^3.1.0, uuid@^3.3.2, uuid@^3.3.3: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -uuid@^8.0.0, uuid@^8.3.0: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache@^2.0.3, v8-compile-cache@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -v8-to-istanbul@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" - integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - -v8-to-istanbul@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz#4229f2a99e367f3f018fa1d5c2b8ec684667c69c" - integrity sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - -validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -validate-npm-package-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= - dependencies: - builtins "^1.0.3" - -validate.io-array@^1.0.3: - version "1.0.6" - resolved "https://registry.yarnpkg.com/validate.io-array/-/validate.io-array-1.0.6.tgz#5b5a2cafd8f8b85abb2f886ba153f2d93a27774d" - integrity sha1-W1osr9j4uFq7L4hroVPy2Tond00= - -validate.io-function@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/validate.io-function/-/validate.io-function-1.0.2.tgz#343a19802ed3b1968269c780e558e93411c0bad7" - integrity sha1-NDoZgC7TsZaCaceA5VjpNBHAutc= - -validate.io-integer-array@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz#2cabde033293a6bcbe063feafe91eaf46b13a089" - integrity sha1-LKveAzKTpry+Bj/q/pHq9GsToIk= - dependencies: - validate.io-array "^1.0.3" - validate.io-integer "^1.0.4" - -validate.io-integer@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/validate.io-integer/-/validate.io-integer-1.0.5.tgz#168496480b95be2247ec443f2233de4f89878068" - integrity sha1-FoSWSAuVviJH7EQ/IjPeT4mHgGg= - dependencies: - validate.io-number "^1.0.3" - -validate.io-number@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/validate.io-number/-/validate.io-number-1.0.3.tgz#f63ffeda248bf28a67a8d48e0e3b461a1665baf8" - integrity sha1-9j/+2iSL8opnqNSODjtGGhZluvg= - -validator@13.7.0: - version "13.7.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" - integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -vega-canvas@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/vega-canvas/-/vega-canvas-1.2.6.tgz#55e032ce9a62acd17229f6bac66d99db3d6879cd" - integrity sha512-rgeYUpslYn/amIfnuv3Sw6n4BGns94OjjZNtUc9IDji6b+K8LGS/kW+Lvay8JX/oFqtulBp8RLcHN6QjqPLA9Q== - -vega-crossfilter@~4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/vega-crossfilter/-/vega-crossfilter-4.0.5.tgz#cf6a5fca60821928f976b32f22cf66cfd9cbeeae" - integrity sha512-yF+iyGP+ZxU7Tcj5yBsMfoUHTCebTALTXIkBNA99RKdaIHp1E690UaGVLZe6xde2n5WaYpho6I/I6wdAW3NXcg== - dependencies: - d3-array "^2.7.1" - vega-dataflow "^5.7.3" - vega-util "^1.15.2" - -vega-dataflow@^5.7.3, vega-dataflow@^5.7.4, vega-dataflow@~5.7.4: - version "5.7.4" - resolved "https://registry.yarnpkg.com/vega-dataflow/-/vega-dataflow-5.7.4.tgz#7cafc0a41b9d0b11dd2e34a513f8b7ca345dfd74" - integrity sha512-JGHTpUo8XGETH3b1V892we6hdjzCWB977ybycIu8DPqRoyrZuj6t1fCVImazfMgQD1LAfJlQybWP+alwKDpKig== - dependencies: - vega-format "^1.0.4" - vega-loader "^4.3.2" - vega-util "^1.16.1" - -vega-embed@^6.2.1: - version "6.18.2" - resolved "https://registry.yarnpkg.com/vega-embed/-/vega-embed-6.18.2.tgz#1fcbf9c1eca1fc58db337efacbca7b9c74db43ca" - integrity sha512-wcDyQPE4J5aiCDc3/suH5RQDvrKkjuLkhzUcbOLwEkNF8/+pp17tS0JghzEvAPNRg+5aG1/N2ydixq8Lk3dOlg== - dependencies: - fast-json-patch "^3.0.0-1" - json-stringify-pretty-compact "^3.0.0" - semver "^7.3.5" - tslib "^2.2.0" - vega-schema-url-parser "^2.2.0" - vega-themes "^2.10.0" - vega-tooltip "^0.25.1" - -vega-encode@~4.8.3: - version "4.8.3" - resolved "https://registry.yarnpkg.com/vega-encode/-/vega-encode-4.8.3.tgz#b3048fb39845d72f18d8dc302ad697f826e0ff83" - integrity sha512-JoRYtaV2Hs8spWLzTu/IjR7J9jqRmuIOEicAaWj6T9NSZrNWQzu2zF3IVsX85WnrIDIRUDaehXaFZvy9uv9RQg== - dependencies: - d3-array "^2.7.1" - d3-interpolate "^2.0.1" - vega-dataflow "^5.7.3" - vega-scale "^7.0.3" - vega-util "^1.15.2" - -vega-event-selector@^3.0.0, vega-event-selector@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/vega-event-selector/-/vega-event-selector-3.0.0.tgz#7b855ac0c3ddb59bc5b5caa0d96dbbc9fbd33a4c" - integrity sha512-Gls93/+7tEJGE3kUuUnxrBIxtvaNeF01VIFB2Q2Of2hBIBvtHX74jcAdDtkh5UhhoYGD8Q1J30P5cqEBEwtPoQ== - -vega-event-selector@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/vega-event-selector/-/vega-event-selector-2.0.6.tgz#6beb00e066b78371dde1a0f40cb5e0bbaecfd8bc" - integrity sha512-UwCu50Sqd8kNZ1X/XgiAY+QAyQUmGFAwyDu7y0T5fs6/TPQnDo/Bo346NgSgINBEhEKOAMY1Nd/rPOk4UEm/ew== - -vega-expression@^5.0.0, vega-expression@~5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vega-expression/-/vega-expression-5.0.0.tgz#938f26689693a1e0d26716030cdaed43ca7abdfb" - integrity sha512-y5+c2frq0tGwJ7vYXzZcfVcIRF/QGfhf2e+bV1Z0iQs+M2lI1II1GPDdmOcMKimpoCVp/D61KUJDIGE1DSmk2w== - dependencies: - "@types/estree" "^0.0.50" - vega-util "^1.16.0" - -vega-expression@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/vega-expression/-/vega-expression-4.0.1.tgz#c03e4fc68a00acac49557faa4e4ed6ac8a59c5fd" - integrity sha512-ZrDj0hP8NmrCpdLFf7Rd/xMUHGoSYsAOTaYp7uXZ2dkEH5x0uPy5laECMc8TiQvL8W+8IrN2HAWCMRthTSRe2Q== - dependencies: - vega-util "^1.16.0" - -vega-force@~4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/vega-force/-/vega-force-4.0.7.tgz#6dc39ecb7889d9102661244d62fbc8d8714162ee" - integrity sha512-pyLKdwXSZ9C1dVIqdJOobvBY29rLvZjvRRTla9BU/nMwAiAGlGi6WKUFdRGdneyGe3zo2nSZDTZlZM/Z5VaQNA== - dependencies: - d3-force "^2.1.1" - vega-dataflow "^5.7.3" - vega-util "^1.15.2" - -vega-format@^1.0.4, vega-format@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vega-format/-/vega-format-1.0.4.tgz#40c0c252d11128738b845ee73d8173f8064d6626" - integrity sha512-oTAeub3KWm6nKhXoYCx1q9G3K43R6/pDMXvqDlTSUtjoY7b/Gixm8iLcir5S9bPjvH40n4AcbZsPmNfL/Up77A== - dependencies: - d3-array "^2.7.1" - d3-format "^2.0.0" - d3-time-format "^3.0.0" - vega-time "^2.0.3" - vega-util "^1.15.2" - -vega-functions@^5.10.0, vega-functions@^5.12.1, vega-functions@~5.12.1: - version "5.12.1" - resolved "https://registry.yarnpkg.com/vega-functions/-/vega-functions-5.12.1.tgz#b69f9ad4cd9f777dbc942587c02261b2f4cdba2c" - integrity sha512-7cHfcjXOj27qEbh2FTzWDl7FJK4xGcMFF7+oiyqa0fp7BU/wNT5YdNV0t5kCX9WjV7mfJWACKV74usLJbyM6GA== - dependencies: - d3-array "^2.7.1" - d3-color "^2.0.0" - d3-geo "^2.0.1" - vega-dataflow "^5.7.3" - vega-expression "^5.0.0" - vega-scale "^7.1.1" - vega-scenegraph "^4.9.3" - vega-selections "^5.3.1" - vega-statistics "^1.7.9" - vega-time "^2.0.4" - vega-util "^1.16.0" - -vega-geo@~4.3.8: - version "4.3.8" - resolved "https://registry.yarnpkg.com/vega-geo/-/vega-geo-4.3.8.tgz#5629d18327bb4f3700cdf05db4aced0a43abbf4a" - integrity sha512-fsGxV96Q/QRgPqOPtMBZdI+DneIiROKTG3YDZvGn0EdV16OG5LzFhbNgLT5GPzI+kTwgLpAsucBHklexlB4kfg== - dependencies: - d3-array "^2.7.1" - d3-color "^2.0.0" - d3-geo "^2.0.1" - vega-canvas "^1.2.5" - vega-dataflow "^5.7.3" - vega-projection "^1.4.5" - vega-statistics "^1.7.9" - vega-util "^1.15.2" - -vega-hierarchy@~4.0.9: - version "4.0.9" - resolved "https://registry.yarnpkg.com/vega-hierarchy/-/vega-hierarchy-4.0.9.tgz#4b4bafbc181a14a280ecdbee8874c0db7e369f47" - integrity sha512-4XaWK6V38/QOZ+vllKKTafiwL25m8Kd+ebHmDV+Q236ONHmqc/gv82wwn9nBeXPEfPv4FyJw2SRoqa2Jol6fug== - dependencies: - d3-hierarchy "^2.0.0" - vega-dataflow "^5.7.3" - vega-util "^1.15.2" - -vega-label@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vega-label/-/vega-label-1.1.0.tgz#0a11ae3ba18d7aed909c51ec67c2a9dde4426c6f" - integrity sha512-LAThIiDEsZxYvbSkvPLJ93eJF+Ts8RXv1IpBh8gmew8XGmaLJvVkzdsMe7WJJwuaVEsK7ZZFyB/Inkp842GW6w== - dependencies: - vega-canvas "^1.2.5" - vega-dataflow "^5.7.3" - vega-scenegraph "^4.9.2" - vega-util "^1.15.2" - -vega-lite@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/vega-lite/-/vega-lite-5.1.1.tgz#7655a75b657540fae663ca7c6b1ba4c44016007f" - integrity sha512-V085gNkbgbmcVC/Q3dJjmIioxcDicxMHvH0FIKOPxdplzt+qU9xGIhQy7scj0tSMYnmAPCayB5oLkkQXFb6w1w== - dependencies: - "@types/clone" "~2.1.1" - array-flat-polyfill "^1.0.1" - clone "~2.1.2" - fast-deep-equal "~3.1.3" - fast-json-stable-stringify "~2.1.0" - json-stringify-pretty-compact "~3.0.0" - tslib "~2.3.1" - vega-event-selector "~2.0.6" - vega-expression "~4.0.1" - vega-util "~1.16.1" - yargs "~17.1.1" - -vega-loader@^4.3.2, vega-loader@^4.3.3, vega-loader@~4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/vega-loader/-/vega-loader-4.4.1.tgz#8f9de46202f33659d1a2737f6e322a9fc3364275" - integrity sha512-dj65i4qlNhK0mOmjuchHgUrF5YUaWrYpx0A8kXA68lBk5Hkx8FNRztkcl07CZJ1+8V81ymEyJii9jzGbhEX0ag== - dependencies: - d3-dsv "^2.0.0" - node-fetch "^2.6.1" - topojson-client "^3.1.0" - vega-format "^1.0.4" - vega-util "^1.16.0" - -vega-parser@~6.1.4: - version "6.1.4" - resolved "https://registry.yarnpkg.com/vega-parser/-/vega-parser-6.1.4.tgz#4868e41af2c9645b6d7daeeb205cfad06b9d465c" - integrity sha512-tORdpWXiH/kkXcpNdbSVEvtaxBuuDtgYp9rBunVW9oLsjFvFXbSWlM1wvJ9ZFSaTfx6CqyTyGMiJemmr1QnTjQ== - dependencies: - vega-dataflow "^5.7.3" - vega-event-selector "^3.0.0" - vega-functions "^5.12.1" - vega-scale "^7.1.1" - vega-util "^1.16.0" - -vega-projection@^1.4.5, vega-projection@~1.4.5: - version "1.4.5" - resolved "https://registry.yarnpkg.com/vega-projection/-/vega-projection-1.4.5.tgz#020cb646b4eaae535359da25f4f48eef8d324af2" - integrity sha512-85kWcPv0zrrNfxescqHtSYpRknilrS0K3CVRZc7IYQxnLtL1oma9WEbrSr1LCmDoCP5hl2Z1kKbomPXkrQX5Ag== - dependencies: - d3-geo "^2.0.1" - d3-geo-projection "^3.0.0" - -vega-regression@~1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/vega-regression/-/vega-regression-1.0.9.tgz#f33da47fe457e03ad134782c11414bcef7b1da82" - integrity sha512-KSr3QbCF0vJEAWFVY2MA9X786oiJncTTr3gqRMPoaLr/Yo3f7OPKXRoUcw36RiWa0WCOEMgTYtM28iK6ZuSgaA== - dependencies: - d3-array "^2.7.1" - vega-dataflow "^5.7.3" - vega-statistics "^1.7.9" - vega-util "^1.15.2" - -vega-runtime@^6.1.3, vega-runtime@~6.1.3: - version "6.1.3" - resolved "https://registry.yarnpkg.com/vega-runtime/-/vega-runtime-6.1.3.tgz#01e18246f7a80cee034a96017ac30113b92c4034" - integrity sha512-gE+sO2IfxMUpV0RkFeQVnHdmPy3K7LjHakISZgUGsDI/ZFs9y+HhBf8KTGSL5pcZPtQsZh3GBQ0UonqL1mp9PA== - dependencies: - vega-dataflow "^5.7.3" - vega-util "^1.15.2" - -vega-scale@^7.0.3, vega-scale@^7.1.1, vega-scale@~7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/vega-scale/-/vega-scale-7.1.1.tgz#b69a38d1980f6fc1093390f796e556be63fdc808" - integrity sha512-yE0to0prA9E5PBJ/XP77TO0BMkzyUVyt7TH5PAwj+CZT7PMsMO6ozihelRhoIiVcP0Ae/ByCEQBUQkzN5zJ0ZA== - dependencies: - d3-array "^2.7.1" - d3-interpolate "^2.0.1" - d3-scale "^3.2.2" - vega-time "^2.0.4" - vega-util "^1.15.2" - -vega-scenegraph@^4.9.2, vega-scenegraph@^4.9.3, vega-scenegraph@^4.9.4, vega-scenegraph@~4.9.4: - version "4.9.4" - resolved "https://registry.yarnpkg.com/vega-scenegraph/-/vega-scenegraph-4.9.4.tgz#468408c1e89703fa9d3450445daabff623de2757" - integrity sha512-QaegQzbFE2yhYLNWAmHwAuguW3yTtQrmwvfxYT8tk0g+KKodrQ5WSmNrphWXhqwtsgVSvtdZkfp2IPeumcOQJg== - dependencies: - d3-path "^2.0.0" - d3-shape "^2.0.0" - vega-canvas "^1.2.5" - vega-loader "^4.3.3" - vega-scale "^7.1.1" - vega-util "^1.15.2" - -vega-schema-url-parser@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/vega-schema-url-parser/-/vega-schema-url-parser-2.2.0.tgz#a0d1e02915adfbfcb1fd517c8c2ebe2419985c1e" - integrity sha512-yAtdBnfYOhECv9YC70H2gEiqfIbVkq09aaE4y/9V/ovEFmH9gPKaEgzIZqgT7PSPQjKhsNkb6jk6XvSoboxOBw== - -vega-selections@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/vega-selections/-/vega-selections-5.3.1.tgz#af5c3cc6532a55a5b692eb0fcc2a1d8d521605a4" - integrity sha512-cm4Srw1WHjcLGXX7GpxiUlfESv8XPu5b6Vh3mqMDPU94P2FO91SR9gei+EtRdt+KCFgIjr//MnRUjg/hAWwjkQ== - dependencies: - vega-expression "^5.0.0" - vega-util "^1.16.0" - -vega-statistics@^1.7.9, vega-statistics@~1.7.10: - version "1.7.10" - resolved "https://registry.yarnpkg.com/vega-statistics/-/vega-statistics-1.7.10.tgz#4353637402e5e96bff2ebd16bd58e2c15cac3018" - integrity sha512-QLb12gcfpDZ9K5h3TLGrlz4UXDH9wSPyg9LLfOJZacxvvJEPohacUQNrGEAVtFO9ccUCerRfH9cs25ZtHsOZrw== - dependencies: - d3-array "^2.7.1" - -vega-themes@^2.10.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/vega-themes/-/vega-themes-2.10.0.tgz#82768b14686e3fbfbdab0e77cb63e12c62b4911e" - integrity sha512-prePRUKFUFGWniuZsJOfkdb+27Gwrrm82yAlVuU+912kcknsx1DVmMSg2yF79f4jdtqnAFIGycZgxoj13SEIuQ== - -vega-time@^2.0.3, vega-time@^2.0.4, vega-time@~2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/vega-time/-/vega-time-2.0.4.tgz#ff308358a831de927caa44e281cdc96f0863ba08" - integrity sha512-U314UDR9+ZlWrD3KBaeH+j/c2WSMdvcZq5yJfFT0yTg1jsBKAQBYFGvl+orackD8Zx3FveHOxx3XAObaQeDX+Q== - dependencies: - d3-array "^2.7.1" - d3-time "^2.0.0" - vega-util "^1.15.2" - -vega-tooltip@^0.25.1: - version "0.25.1" - resolved "https://registry.yarnpkg.com/vega-tooltip/-/vega-tooltip-0.25.1.tgz#cb7e438438649eb46896e7bee6f54e25d25b3c09" - integrity sha512-ugGwGi2/p3OpB8N15xieuzP8DyV5DreqMWcmJ9zpWT8GlkyKtef4dGRXnvHeHQ+iJFmWrq4oZJ+kLTrdiECjAg== - dependencies: - vega-util "^1.16.0" - -vega-transforms@~4.9.4: - version "4.9.4" - resolved "https://registry.yarnpkg.com/vega-transforms/-/vega-transforms-4.9.4.tgz#5cf6b91bda9f184bbbaba63838be8e5e6a571235" - integrity sha512-JGBhm5Bf6fiGTUSB5Qr5ckw/KU9FJcSV5xIe/y4IobM/i/KNwI1i1fP45LzP4F4yZc0DMTwJod2UvFHGk9plKA== - dependencies: - d3-array "^2.7.1" - vega-dataflow "^5.7.4" - vega-statistics "^1.7.9" - vega-time "^2.0.4" - vega-util "^1.16.1" - -vega-typings@~0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/vega-typings/-/vega-typings-0.22.0.tgz#a7cd4ce8194d332dc7a21a2ce09c9261a0d29c66" - integrity sha512-TgBGRkZHQgcduGsoFKq3Scpn6eNY4L3p0YKRhgCPVU3HEaCeYkPFGaR8ynK+XrKmvrqpDv0YHIOwCt7Gn3RpCA== - dependencies: - vega-event-selector "^3.0.0" - vega-expression "^5.0.0" - vega-util "^1.15.2" - -vega-util@^1.15.2, vega-util@^1.16.0, vega-util@^1.16.1, vega-util@~1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/vega-util/-/vega-util-1.17.0.tgz#b72ae0baa97f943bf591f8f5bb27ceadf06834ac" - integrity sha512-HTaydZd9De3yf+8jH66zL4dXJ1d1p5OIFyoBzFiOli4IJbwkL1jrefCKz6AHDm1kYBzDJ0X4bN+CzZSCTvNk1w== - -vega-util@~1.16.1: - version "1.16.1" - resolved "https://registry.yarnpkg.com/vega-util/-/vega-util-1.16.1.tgz#992bf3c3b6e145797214d99862841baea417ba39" - integrity sha512-FdgD72fmZMPJE99FxvFXth0IL4BbLA93WmBg/lvcJmfkK4Uf90WIlvGwaIUdSePIsdpkZjBPyQcHMQ8OcS8Smg== - -vega-view-transforms@~4.5.8: - version "4.5.8" - resolved "https://registry.yarnpkg.com/vega-view-transforms/-/vega-view-transforms-4.5.8.tgz#c8dc42c3c7d4aa725d40b8775180c9f23bc98f4e" - integrity sha512-966m7zbzvItBL8rwmF2nKG14rBp7q+3sLCKWeMSUrxoG+M15Smg5gWEGgwTG3A/RwzrZ7rDX5M1sRaAngRH25g== - dependencies: - vega-dataflow "^5.7.3" - vega-scenegraph "^4.9.2" - vega-util "^1.15.2" - -vega-view@~5.10.1: - version "5.10.1" - resolved "https://registry.yarnpkg.com/vega-view/-/vega-view-5.10.1.tgz#b69348bb32a9845a1bd341fdd946df98684fadc3" - integrity sha512-4xvQ5KZcgKdZx1Z7jjenCUumvlyr/j4XcHLRf9gyeFrFvvS596dVpL92V8twhV6O++DmS2+fj+rHagO8Di4nMg== - dependencies: - d3-array "^2.7.1" - d3-timer "^2.0.0" - vega-dataflow "^5.7.3" - vega-format "^1.0.4" - vega-functions "^5.10.0" - vega-runtime "^6.1.3" - vega-scenegraph "^4.9.4" - vega-util "^1.16.1" - -vega-voronoi@~4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/vega-voronoi/-/vega-voronoi-4.1.5.tgz#e7af574d4c27fd9cb12d70082f12c6f59b80b445" - integrity sha512-950IkgCFLj0zG33EWLAm1hZcp+FMqWcNQliMYt+MJzOD5S4MSpZpZ7K4wp2M1Jktjw/CLKFL9n38JCI0i3UonA== - dependencies: - d3-delaunay "^5.3.0" - vega-dataflow "^5.7.3" - vega-util "^1.15.2" - -vega-wordcloud@~4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/vega-wordcloud/-/vega-wordcloud-4.1.3.tgz#ce90900333f4e0d3ee706ba4f36bb0905f8b4a9f" - integrity sha512-is4zYn9FMAyp9T4SAcz2P/U/wqc0Lx3P5YtpWKCbOH02a05vHjUQrQ2TTPOuvmMfAEDCSKvbMSQIJMOE018lJA== - dependencies: - vega-canvas "^1.2.5" - vega-dataflow "^5.7.3" - vega-scale "^7.1.1" - vega-statistics "^1.7.9" - vega-util "^1.15.2" - -vega@^5.20.0: - version "5.21.0" - resolved "https://registry.yarnpkg.com/vega/-/vega-5.21.0.tgz#f3d858d7544bfe4ffa3d8cd43d9ea978bf7391e8" - integrity sha512-yqqRa9nAqYoAxe7sVhRpsh0b001fly7Yx05klPkXmrvzjxXd07gClW1mOuGgSnVQqo7jTp/LYgbO1bD37FbEig== - dependencies: - vega-crossfilter "~4.0.5" - vega-dataflow "~5.7.4" - vega-encode "~4.8.3" - vega-event-selector "~3.0.0" - vega-expression "~5.0.0" - vega-force "~4.0.7" - vega-format "~1.0.4" - vega-functions "~5.12.1" - vega-geo "~4.3.8" - vega-hierarchy "~4.0.9" - vega-label "~1.1.0" - vega-loader "~4.4.1" - vega-parser "~6.1.4" - vega-projection "~1.4.5" - vega-regression "~1.0.9" - vega-runtime "~6.1.3" - vega-scale "~7.1.1" - vega-scenegraph "~4.9.4" - vega-statistics "~1.7.10" - vega-time "~2.0.4" - vega-transforms "~4.9.4" - vega-typings "~0.22.0" - vega-util "~1.17.0" - vega-view "~5.10.1" - vega-view-transforms "~4.5.8" - vega-voronoi "~4.1.5" - vega-wordcloud "~4.1.3" - -verdaccio-audit@11.0.0-6-next.23: - version "11.0.0-6-next.23" - resolved "https://registry.yarnpkg.com/verdaccio-audit/-/verdaccio-audit-11.0.0-6-next.23.tgz#a4163abe96cb2b90884080f94bde3db1e30a53f4" - integrity sha512-4TmBfglknSIgLVKUOrhx9ArtI715Ju2SJnyoP0e7DIM1vEdw3Njt1GTG44L47r+n+rB7I6rsrM0/MxKffUmjNQ== - dependencies: - "@verdaccio/config" "6.0.0-6-next.60" - "@verdaccio/core" "6.0.0-6-next.60" - express "4.18.2" - https-proxy-agent "5.0.1" - node-fetch cjs - -verdaccio-htpasswd@10.5.2: - version "10.5.2" - resolved "https://registry.yarnpkg.com/verdaccio-htpasswd/-/verdaccio-htpasswd-10.5.2.tgz#981f39ad1c8a002926469b50927f077fc8676367" - integrity sha512-bO5Wm8w07pWswNvwFWjNEoznuUU37CcfblcrU0Ci8c038EgTu2V47uwh4AyZ4PTK6ps9oxHqA7a1b+83sY0OkA== - dependencies: - "@verdaccio/file-locking" "10.3.0" - apache-md5 "1.1.8" - bcryptjs "2.4.3" - http-errors "2.0.0" - unix-crypt-td-js "1.1.4" - -verdaccio@^5.20.1: - version "5.21.1" - resolved "https://registry.yarnpkg.com/verdaccio/-/verdaccio-5.21.1.tgz#a88ab1f8bfe623e535c88ddcaa1b95d2bea2abee" - integrity sha512-SbqeKxmcUW1G9AYo8cmAPAlWW6YpNR8Q6LVJrfP+4s9gQ496s8cvhj0yAX8nl1k3+DAEZBuGcrgfAF0kORYXpA== - dependencies: - "@verdaccio/config" "6.0.0-6-next.61" - "@verdaccio/core" "6.0.0-6-next.61" - "@verdaccio/local-storage" "10.3.1" - "@verdaccio/logger-7" "6.0.0-6-next.6" - "@verdaccio/middleware" "6.0.0-6-next.40" - "@verdaccio/streams" "10.2.0" - "@verdaccio/tarball" "11.0.0-6-next.30" - "@verdaccio/ui-theme" "6.0.0-6-next.61" - "@verdaccio/url" "11.0.0-6-next.27" - "@verdaccio/utils" "6.0.0-6-next.29" - JSONStream "1.3.5" - async "3.2.4" - body-parser "1.20.1" - clipanion "3.2.0-rc.14" - compression "1.7.4" - cookies "0.8.0" - cors "2.8.5" - debug "^4.3.4" - envinfo "7.8.1" - express "4.18.2" - fast-safe-stringify "2.1.1" - handlebars "4.7.7" - js-yaml "4.1.0" - jsonwebtoken "9.0.0" - kleur "4.1.5" - lodash "4.17.21" - lunr-mutable-indexes "2.3.2" - mime "3.0.0" - mkdirp "1.0.4" - mv "2.1.1" - pkginfo "0.4.1" - request "2.88.0" - semver "7.3.8" - validator "13.7.0" - verdaccio-audit "11.0.0-6-next.23" - verdaccio-htpasswd "10.5.2" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - -vscode-textmate@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" - integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== - -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - -walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= - dependencies: - makeerror "1.0.x" - -warning@^4.0.2, warning@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - -watch@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" - integrity sha1-NApxe952Vyb6CqB9ch4BR6VR3ww= - dependencies: - exec-sh "^0.2.0" - minimist "^1.2.0" - -watchpack-chokidar2@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" - integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== - dependencies: - chokidar "^2.1.8" - -watchpack@^1.7.4: - version "1.7.5" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" - integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== - dependencies: - graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.1" - -watchpack@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce" - integrity sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - -wcwidth@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - -webpack-bundle-analyzer@^3.6.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz#f6f94db108fb574e415ad313de41a2707d33ef3c" - integrity sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - bfj "^6.1.1" - chalk "^2.4.1" - commander "^2.18.0" - ejs "^2.6.1" - express "^4.16.3" - filesize "^3.6.1" - gzip-size "^5.0.0" - lodash "^4.17.19" - mkdirp "^0.5.1" - opener "^1.5.1" - ws "^6.0.0" - -webpack-cli@^4.1.0: - version "4.7.2" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.7.2.tgz#a718db600de6d3906a4357e059ae584a89f4c1a5" - integrity sha512-mEoLmnmOIZQNiRl0ebnjzQ74Hk0iKS5SiEEnpq3dRezoyR3yPaeQZCMCe+db4524pj1Pd5ghZXjT41KLzIhSLw== - dependencies: - "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.0.4" - "@webpack-cli/info" "^1.3.0" - "@webpack-cli/serve" "^1.5.1" - colorette "^1.2.1" - commander "^7.0.0" - execa "^5.0.0" - fastest-levenshtein "^1.0.12" - import-local "^3.0.2" - interpret "^2.2.0" - rechoir "^0.7.0" - v8-compile-cache "^2.2.0" - webpack-merge "^5.7.3" - -webpack-dev-middleware@^3.7.0: - version "3.7.3" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" - integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== - dependencies: - memory-fs "^0.4.1" - mime "^2.4.4" - mkdirp "^0.5.1" - range-parser "^1.2.1" - webpack-log "^2.0.0" - -webpack-hot-middleware@^2.25.0: - version "2.25.0" - resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.25.0.tgz#4528a0a63ec37f8f8ef565cf9e534d57d09fe706" - integrity sha512-xs5dPOrGPCzuRXNi8F6rwhawWvQQkeli5Ro48PRuQh8pYPCPmNnltP9itiUPT4xI8oW+y0m59lyyeQk54s5VgA== - dependencies: - ansi-html "0.0.7" - html-entities "^1.2.0" - querystring "^0.2.0" - strip-ansi "^3.0.0" - -webpack-log@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d" - integrity sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA== - dependencies: - chalk "^2.1.0" - log-symbols "^2.1.0" - loglevelnext "^1.0.1" - uuid "^3.1.0" - -webpack-log@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" - integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== - dependencies: - ansi-colors "^3.0.0" - uuid "^3.3.2" - -webpack-merge@^5.1.2, webpack-merge@^5.7.3: - version "5.8.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" - integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== - dependencies: - clone-deep "^4.0.1" - wildcard "^2.0.0" - -webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack-sources@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.0.tgz#9ed2de69b25143a4c18847586ad9eccb19278cfa" - integrity sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ== - dependencies: - source-list-map "^2.0.1" - source-map "^0.6.1" - -webpack-virtual-modules@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.2.2.tgz#20863dc3cb6bb2104729fff951fbe14b18bd0299" - integrity sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA== - dependencies: - debug "^3.0.0" - -webpack@^4.43.0: - version "4.46.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" - integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" - -webpack@^5.41.1: - version "5.44.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.44.0.tgz#97b13a02bd79fb71ac6301ce697920660fa214a1" - integrity sha512-I1S1w4QLoKmH19pX6YhYN0NiSXaWY8Ou00oA+aMcr9IUGeF5azns+IKBkfoAAG9Bu5zOIzZt/mN35OffBya8AQ== - dependencies: - "@types/eslint-scope" "^3.7.0" - "@types/estree" "^0.0.50" - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/wasm-edit" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - acorn "^8.4.1" - browserslist "^4.14.5" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.8.0" - es-module-lexer "^0.7.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.4" - json-parse-better-errors "^1.0.2" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.0.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.1.3" - watchpack "^2.2.0" - webpack-sources "^2.3.0" - -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-fetch@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" - integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== - -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^1.2.9, which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -widest-line@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" - integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== - dependencies: - string-width "^4.0.0" - -wildcard@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" - integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== - -window-size@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" - integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY= - -word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - -worker-loader@^3.0.2: - version "3.0.8" - resolved "https://registry.yarnpkg.com/worker-loader/-/worker-loader-3.0.8.tgz#5fc5cda4a3d3163d9c274a4e3a811ce8b60dbb37" - integrity sha512-XQyQkIFeRVC7f7uRhFdNMe/iJOdO6zxAaR3EWbDp45v3mDhrTi+++oswKNxShUNjPC/1xUp5DB29YKLhFo129g== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -worker-rpc@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" - integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg== - dependencies: - microevent.ts "~0.1.1" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^2.4.2: - version "2.4.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" - integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - -write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -write-json-file@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" - integrity sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ== - dependencies: - detect-indent "^5.0.0" - graceful-fs "^4.1.15" - make-dir "^2.1.0" - pify "^4.0.1" - sort-keys "^2.0.0" - write-file-atomic "^2.4.2" - -write-json-file@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" - integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== - dependencies: - detect-indent "^6.0.0" - graceful-fs "^4.1.15" - is-plain-obj "^2.0.0" - make-dir "^3.0.0" - sort-keys "^4.0.0" - write-file-atomic "^3.0.0" - -write-pkg@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" - integrity sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA== - dependencies: - sort-keys "^2.0.0" - type-fest "^0.4.1" - write-json-file "^3.2.0" - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -ws@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.2.tgz#96c1d08b3fefda1d5c1e33700d3bfaa9be2d5608" - integrity sha512-t+WGpsNxhMR4v6EClXS8r8km5ZljKJzyGhJf7goJz9k5Ye3+b5Bvno5rjqPuIBn5mnn5GBb7o8IrIWHxX1qOLQ== - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - -ws@^6.0.0, ws@^6.2.1: - version "6.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" - integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== - dependencies: - async-limiter "~1.0.0" - -ws@^7.4.5, ws@^7.4.6: - version "7.5.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.2.tgz#09cc8fea3bec1bc5ed44ef51b42f945be36900f6" - integrity sha512-lkF7AWRicoB9mAgjeKbGqVUekLnSNO4VjKVnuPHpQeOxZOErX6BPXwJk70nFslRCEEA8EVW7ZjKwXaP9N+1sKQ== - -xdg-basedir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" - integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xml@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" - integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= - -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -xmldom@0.1.19: - version "0.1.19" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.19.tgz#631fc07776efd84118bf25171b37ed4d075a0abc" - integrity sha1-Yx/Ad3bv2EEYvyUXGzftTQdaCrw= - -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -xterm-addon-fit@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596" - integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ== - -xterm-addon-web-links@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.6.0.tgz#0296cb6c99588847894670d998c9ea6a6aeb26ee" - integrity sha512-H6XzjWWZu8FBo+fnYpxdPk9w5M6drbsvwPEJZGRS38MihiQaVFpKlCMKdfRgDbKGE530tw1yH54rhpZfHgt2/A== - -xterm@~4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d" - integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ== - -y-codemirror@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/y-codemirror/-/y-codemirror-3.0.1.tgz#d8a4e43cf46b5b557e0f03b7bbb65773ff436278" - integrity sha512-TsLSoouAZxkxOKbmTj7qdwZNS0lZMVqIdp7/j9EgUUqYj0remZYDGl6VBABrmp9UX1QvX6RoXXqzbNhftgfCbA== - dependencies: - lib0 "^0.2.42" - -y-leveldb@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/y-leveldb/-/y-leveldb-0.1.0.tgz#8b60c1af020252445875ebc70d52666017bcb038" - integrity sha512-sMuitVrsAUNh+0b66I42nAuW3lCmez171uP4k0ePcTAJ+c+Iw9w4Yq3wwiyrDMFXBEyQSjSF86Inc23wEvWnxw== - dependencies: - level "^6.0.1" - lib0 "^0.2.31" - -y-protocols@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/y-protocols/-/y-protocols-1.0.5.tgz#91d574250060b29fcac8f8eb5e276fbad594245e" - integrity sha512-Wil92b7cGk712lRHDqS4T90IczF6RkcvCwAD0A2OPg+adKmOe+nOiT/N2hvpQIWS3zfjmtL4CPaH5sIW1Hkm/A== - dependencies: - lib0 "^0.2.42" - -y-websocket@^1.4.6: - version "1.4.6" - resolved "https://registry.yarnpkg.com/y-websocket/-/y-websocket-1.4.6.tgz#61499fe7df63179ed2ba5a525a1514dfb406264c" - integrity sha512-QAmFPlcjUWbdtueMjP/z7CpIJ3pyQbBiPsXyjeeXfSF5VJwV7aqlbU16a0YOsiSQwHCeLO8N2mYs8WsrKfmE7A== - dependencies: - lib0 "^0.2.52" - lodash.debounce "^4.0.8" - y-protocols "^1.0.5" - optionalDependencies: - ws "^6.2.1" - y-leveldb "^0.1.0" - -y18n@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" - integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== - -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.0.tgz#882c762992888b4144bffdec5745df340627fdd3" - integrity sha512-auf7Gi6QwO7HW//GA9seGvTXVGWl1CM/ADWh1+RxtXr6XOxnT65ovDl9fTi4e0monEyJxCHqDpF6QnFDXmJE4g== - -yaml@^1.10.0, yaml@^1.7.2: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.7: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-parser@^18.1.2, yargs-parser@^18.1.3: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs@3.32.0: - version "3.32.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" - integrity sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU= - dependencies: - camelcase "^2.0.1" - cliui "^3.0.3" - decamelize "^1.1.1" - os-locale "^1.4.0" - string-width "^1.0.1" - window-size "^0.1.4" - y18n "^3.2.0" - -yargs@^15.4.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - 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" - -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yargs@~17.1.1: - version "17.1.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.1.tgz#c2a8091564bdb196f7c0a67c1d12e5b85b8067ba" - integrity sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yarn-deduplicate@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/yarn-deduplicate/-/yarn-deduplicate-2.1.1.tgz#500a3010e4bdee3c3250936e210910c7cae3d75d" - integrity sha512-lbFJGOMnqG/ncGjNBUt+JG4qfAGqeh8o9i4i5LXqNBdQ8ov8av6T1jizWQqr+zLPLCOqp/BYBZz8FymPQSR4RA== - dependencies: - "@yarnpkg/lockfile" "^1.1.0" - commander "^5.1.0" - semver "^7.3.2" - -yarn@1.21.1: - version "1.21.1" - resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.21.1.tgz#1d5da01a9a03492dc4a5957befc1fd12da83d89c" - integrity sha512-dQgmJv676X/NQczpbiDtc2hsE/pppGDJAzwlRiADMTvFzYbdxPj2WO4PcNyriSt2c4jsCMpt8UFRKHUozt21GQ== - -yjs@^13.5.17, yjs@^13.5.40: - version "13.5.42" - resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.5.42.tgz#949f7d091ded6e2621a5798982a9631b79e1b62c" - integrity sha512-3aYBPeUSBUCs/vCOYolbyzhsQ6IDm1DeJgfhHVbW+6kq8YhWjkk2SUhYtBxd3lZPNsqmJGzYH9shKINhSVbEzw== - dependencies: - lib0 "^0.2.49" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -yup@0.32.11: - version "0.32.11" - resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" - integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg== - dependencies: - "@babel/runtime" "^7.15.4" - "@types/lodash" "^4.14.175" - lodash "^4.17.21" - lodash-es "^4.17.21" - nanoclone "^0.2.1" - property-expr "^2.0.4" - toposort "^2.0.2" +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"@ampproject/remapping@npm:^2.2.0": + version: 2.2.0 + resolution: "@ampproject/remapping@npm:2.2.0" + dependencies: + "@jridgewell/gen-mapping": ^0.1.0 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: d74d170d06468913921d72430259424b7e4c826b5a7d39ff839a29d547efb97dc577caa8ba3fb5cf023624e9af9d09651afc3d4112a45e2050328abc9b3a2292 + languageName: node + linkType: hard + +"@arcanis/slice-ansi@npm:^1.1.1": + version: 1.1.1 + resolution: "@arcanis/slice-ansi@npm:1.1.1" + dependencies: + grapheme-splitter: ^1.0.4 + checksum: 14ed60cb45750d386c64229ac7bab20e10eedc193503fa4decff764162d329d6d3363ed2cd3debec833186ee54affe4f824f6e8eff531295117fd1ebda200270 + languageName: node + linkType: hard + +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/code-frame@npm:7.18.6" + dependencies: + "@babel/highlight": ^7.18.6 + checksum: 195e2be3172d7684bf95cff69ae3b7a15a9841ea9d27d3c843662d50cdd7d6470fd9c8e64be84d031117e4a4083486effba39f9aef6bbb2c89f7f21bcfba33ba + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.1, @babel/compat-data@npm:^7.20.5": + version: 7.21.0 + resolution: "@babel/compat-data@npm:7.21.0" + checksum: dbf632c532f9c75ba0be7d1dc9f6cd3582501af52f10a6b90415d634ec5878735bd46064c91673b10317af94d4cc99c4da5bd9d955978cdccb7905fc33291e4d + languageName: node + linkType: hard + +"@babel/core@npm:^7.10.2, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": + version: 7.21.0 + resolution: "@babel/core@npm:7.21.0" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.18.6 + "@babel/generator": ^7.21.0 + "@babel/helper-compilation-targets": ^7.20.7 + "@babel/helper-module-transforms": ^7.21.0 + "@babel/helpers": ^7.21.0 + "@babel/parser": ^7.21.0 + "@babel/template": ^7.20.7 + "@babel/traverse": ^7.21.0 + "@babel/types": ^7.21.0 + convert-source-map: ^1.7.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.2 + semver: ^6.3.0 + checksum: 357f4dd3638861ceebf6d95ff49ad8b902065ee8b7b352621deed5666c2a6d702a48ca7254dba23ecae2a0afb67d20f90db7dd645c3b75e35e72ad9776c671aa + languageName: node + linkType: hard + +"@babel/generator@npm:^7.21.0, @babel/generator@npm:^7.21.1, @babel/generator@npm:^7.7.2": + version: 7.21.1 + resolution: "@babel/generator@npm:7.21.1" + dependencies: + "@babel/types": ^7.21.0 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 69085a211ff91a7a608ee3f86e6fcb9cf5e724b756d792a713b0c328a671cd3e423e1ef1b12533f366baba0616caffe0a7ba9d328727eab484de5961badbef00 + languageName: node + linkType: hard + +"@babel/helper-annotate-as-pure@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/helper-annotate-as-pure@npm:7.18.6" + dependencies: + "@babel/types": ^7.18.6 + checksum: 88ccd15ced475ef2243fdd3b2916a29ea54c5db3cd0cfabf9d1d29ff6e63b7f7cd1c27264137d7a40ac2e978b9b9a542c332e78f40eb72abe737a7400788fc1b + languageName: node + linkType: hard + +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.18.6": + version: 7.18.9 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.18.9" + dependencies: + "@babel/helper-explode-assignable-expression": ^7.18.6 + "@babel/types": ^7.18.9 + checksum: b4bc214cb56329daff6cc18a7f7a26aeafb55a1242e5362f3d47fe3808421f8c7cd91fff95d6b9b7ccb67e14e5a67d944e49dbe026942bfcbfda19b1c72a8e72 + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.17.7, @babel/helper-compilation-targets@npm:^7.18.9, @babel/helper-compilation-targets@npm:^7.20.0, @babel/helper-compilation-targets@npm:^7.20.7": + version: 7.20.7 + resolution: "@babel/helper-compilation-targets@npm:7.20.7" + dependencies: + "@babel/compat-data": ^7.20.5 + "@babel/helper-validator-option": ^7.18.6 + browserslist: ^4.21.3 + lru-cache: ^5.1.1 + semver: ^6.3.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 8c32c873ba86e2e1805b30e0807abd07188acbe00ebb97576f0b09061cc65007f1312b589eccb4349c5a8c7f8bb9f2ab199d41da7030bf103d9f347dcd3a3cf4 + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helper-create-class-features-plugin@npm:7.21.0" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-function-name": ^7.21.0 + "@babel/helper-member-expression-to-functions": ^7.21.0 + "@babel/helper-optimise-call-expression": ^7.18.6 + "@babel/helper-replace-supers": ^7.20.7 + "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 + "@babel/helper-split-export-declaration": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 3e781d91d1056ea9b3a0395f3017492594a8b86899119b4a1645227c31727b8bec9bc8f6b72e86b1c5cf2dd6690893d2e8c5baff4974c429e616ead089552a21 + languageName: node + linkType: hard + +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.20.5": + version: 7.21.0 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.21.0" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + regexpu-core: ^5.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 63a6396a4e9444edc7e97617845583ea5cf059573d0b4cc566869f38576d543e37fde0edfcc21d6dfb7962ed241e909561714dc41c5213198bac04e0983b04f2 + languageName: node + linkType: hard + +"@babel/helper-define-polyfill-provider@npm:^0.3.3": + version: 0.3.3 + resolution: "@babel/helper-define-polyfill-provider@npm:0.3.3" + dependencies: + "@babel/helper-compilation-targets": ^7.17.7 + "@babel/helper-plugin-utils": ^7.16.7 + debug: ^4.1.1 + lodash.debounce: ^4.0.8 + resolve: ^1.14.2 + semver: ^6.1.2 + peerDependencies: + "@babel/core": ^7.4.0-0 + checksum: 8e3fe75513302e34f6d92bd67b53890e8545e6c5bca8fe757b9979f09d68d7e259f6daea90dc9e01e332c4f8781bda31c5fe551c82a277f9bc0bec007aed497c + languageName: node + linkType: hard + +"@babel/helper-environment-visitor@npm:^7.18.9": + version: 7.18.9 + resolution: "@babel/helper-environment-visitor@npm:7.18.9" + checksum: b25101f6162ddca2d12da73942c08ad203d7668e06663df685634a8fde54a98bc015f6f62938e8554457a592a024108d45b8f3e651fd6dcdb877275b73cc4420 + languageName: node + linkType: hard + +"@babel/helper-explode-assignable-expression@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/helper-explode-assignable-expression@npm:7.18.6" + dependencies: + "@babel/types": ^7.18.6 + checksum: 225cfcc3376a8799023d15dc95000609e9d4e7547b29528c7f7111a0e05493ffb12c15d70d379a0bb32d42752f340233c4115bded6d299bc0c3ab7a12be3d30f + languageName: node + linkType: hard + +"@babel/helper-function-name@npm:^7.18.9, @babel/helper-function-name@npm:^7.19.0, @babel/helper-function-name@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helper-function-name@npm:7.21.0" + dependencies: + "@babel/template": ^7.20.7 + "@babel/types": ^7.21.0 + checksum: d63e63c3e0e3e8b3138fa47b0cd321148a300ef12b8ee951196994dcd2a492cc708aeda94c2c53759a5c9177fffaac0fd8778791286746f72a000976968daf4e + languageName: node + linkType: hard + +"@babel/helper-hoist-variables@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/helper-hoist-variables@npm:7.18.6" + dependencies: + "@babel/types": ^7.18.6 + checksum: fd9c35bb435fda802bf9ff7b6f2df06308a21277c6dec2120a35b09f9de68f68a33972e2c15505c1a1a04b36ec64c9ace97d4a9e26d6097b76b4396b7c5fa20f + languageName: node + linkType: hard + +"@babel/helper-member-expression-to-functions@npm:^7.20.7, @babel/helper-member-expression-to-functions@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helper-member-expression-to-functions@npm:7.21.0" + dependencies: + "@babel/types": ^7.21.0 + checksum: 49cbb865098195fe82ba22da3a8fe630cde30dcd8ebf8ad5f9a24a2b685150c6711419879cf9d99b94dad24cff9244d8c2a890d3d7ec75502cd01fe58cff5b5d + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/helper-module-imports@npm:7.18.6" + dependencies: + "@babel/types": ^7.18.6 + checksum: f393f8a3b3304b1b7a288a38c10989de754f01d29caf62ce7c4e5835daf0a27b81f3ac687d9d2780d39685aae7b55267324b512150e7b2be967b0c493b6a1def + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.18.6, @babel/helper-module-transforms@npm:^7.20.11, @babel/helper-module-transforms@npm:^7.21.0, @babel/helper-module-transforms@npm:^7.21.2": + version: 7.21.2 + resolution: "@babel/helper-module-transforms@npm:7.21.2" + dependencies: + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-module-imports": ^7.18.6 + "@babel/helper-simple-access": ^7.20.2 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/helper-validator-identifier": ^7.19.1 + "@babel/template": ^7.20.7 + "@babel/traverse": ^7.21.2 + "@babel/types": ^7.21.2 + checksum: 8a1c129a4f90bdf97d8b6e7861732c9580f48f877aaaafbc376ce2482febebcb8daaa1de8bc91676d12886487603f8c62a44f9e90ee76d6cac7f9225b26a49e1 + languageName: node + linkType: hard + +"@babel/helper-optimise-call-expression@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/helper-optimise-call-expression@npm:7.18.6" + dependencies: + "@babel/types": ^7.18.6 + checksum: e518fe8418571405e21644cfb39cf694f30b6c47b10b006609a92469ae8b8775cbff56f0b19732343e2ea910641091c5a2dc73b56ceba04e116a33b0f8bd2fbd + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.16.7, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.18.9, @babel/helper-plugin-utils@npm:^7.19.0, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.20.2 + resolution: "@babel/helper-plugin-utils@npm:7.20.2" + checksum: f6cae53b7fdb1bf3abd50fa61b10b4470985b400cc794d92635da1e7077bb19729f626adc0741b69403d9b6e411cddddb9c0157a709cc7c4eeb41e663be5d74b + languageName: node + linkType: hard + +"@babel/helper-remap-async-to-generator@npm:^7.18.9": + version: 7.18.9 + resolution: "@babel/helper-remap-async-to-generator@npm:7.18.9" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-wrap-function": ^7.18.9 + "@babel/types": ^7.18.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 4be6076192308671b046245899b703ba090dbe7ad03e0bea897bb2944ae5b88e5e85853c9d1f83f643474b54c578d8ac0800b80341a86e8538264a725fbbefec + languageName: node + linkType: hard + +"@babel/helper-replace-supers@npm:^7.18.6, @babel/helper-replace-supers@npm:^7.20.7": + version: 7.20.7 + resolution: "@babel/helper-replace-supers@npm:7.20.7" + dependencies: + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-member-expression-to-functions": ^7.20.7 + "@babel/helper-optimise-call-expression": ^7.18.6 + "@babel/template": ^7.20.7 + "@babel/traverse": ^7.20.7 + "@babel/types": ^7.20.7 + checksum: b8e0087c9b0c1446e3c6f3f72b73b7e03559c6b570e2cfbe62c738676d9ebd8c369a708cf1a564ef88113b4330750a50232ee1131d303d478b7a5e65e46fbc7c + languageName: node + linkType: hard + +"@babel/helper-simple-access@npm:^7.20.2": + version: 7.20.2 + resolution: "@babel/helper-simple-access@npm:7.20.2" + dependencies: + "@babel/types": ^7.20.2 + checksum: ad1e96ee2e5f654ffee2369a586e5e8d2722bf2d8b028a121b4c33ebae47253f64d420157b9f0a8927aea3a9e0f18c0103e74fdd531815cf3650a0a4adca11a1 + languageName: node + linkType: hard + +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0": + version: 7.20.0 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.20.0" + dependencies: + "@babel/types": ^7.20.0 + checksum: 34da8c832d1c8a546e45d5c1d59755459ffe43629436707079989599b91e8c19e50e73af7a4bd09c95402d389266731b0d9c5f69e372d8ebd3a709c05c80d7dd + languageName: node + linkType: hard + +"@babel/helper-split-export-declaration@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/helper-split-export-declaration@npm:7.18.6" + dependencies: + "@babel/types": ^7.18.6 + checksum: c6d3dede53878f6be1d869e03e9ffbbb36f4897c7cc1527dc96c56d127d834ffe4520a6f7e467f5b6f3c2843ea0e81a7819d66ae02f707f6ac057f3d57943a2b + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.19.4": + version: 7.19.4 + resolution: "@babel/helper-string-parser@npm:7.19.4" + checksum: b2f8a3920b30dfac81ec282ac4ad9598ea170648f8254b10f475abe6d944808fb006aab325d3eb5a8ad3bea8dfa888cfa6ef471050dae5748497c110ec060943 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1": + version: 7.19.1 + resolution: "@babel/helper-validator-identifier@npm:7.19.1" + checksum: 0eca5e86a729162af569b46c6c41a63e18b43dbe09fda1d2a3c8924f7d617116af39cac5e4cd5d431bb760b4dca3c0970e0c444789b1db42bcf1fa41fbad0a3a + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.18.6": + version: 7.21.0 + resolution: "@babel/helper-validator-option@npm:7.21.0" + checksum: 8ece4c78ffa5461fd8ab6b6e57cc51afad59df08192ed5d84b475af4a7193fc1cb794b59e3e7be64f3cdc4df7ac78bf3dbb20c129d7757ae078e6279ff8c2f07 + languageName: node + linkType: hard + +"@babel/helper-wrap-function@npm:^7.18.9": + version: 7.20.5 + resolution: "@babel/helper-wrap-function@npm:7.20.5" + dependencies: + "@babel/helper-function-name": ^7.19.0 + "@babel/template": ^7.18.10 + "@babel/traverse": ^7.20.5 + "@babel/types": ^7.20.5 + checksum: 11a6fc28334368a193a9cb3ad16f29cd7603bab958433efc82ebe59fa6556c227faa24f07ce43983f7a85df826f71d441638442c4315e90a554fe0a70ca5005b + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helpers@npm:7.21.0" + dependencies: + "@babel/template": ^7.20.7 + "@babel/traverse": ^7.21.0 + "@babel/types": ^7.21.0 + checksum: 9370dad2bb665c551869a08ac87c8bdafad53dbcdce1f5c5d498f51811456a3c005d9857562715151a0f00b2e912ac8d89f56574f837b5689f5f5072221cdf54 + languageName: node + linkType: hard + +"@babel/highlight@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/highlight@npm:7.18.6" + dependencies: + "@babel/helper-validator-identifier": ^7.18.6 + chalk: ^2.0.0 + js-tokens: ^4.0.0 + checksum: 92d8ee61549de5ff5120e945e774728e5ccd57fd3b2ed6eace020ec744823d4a98e242be1453d21764a30a14769ecd62170fba28539b211799bbaf232bbb2789 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.0, @babel/parser@npm:^7.21.2": + version: 7.21.2 + resolution: "@babel/parser@npm:7.21.2" + bin: + parser: ./bin/babel-parser.js + checksum: e2b89de2c63d4cdd2cafeaea34f389bba729727eec7a8728f736bc472a59396059e3e9fe322c9bed8fd126d201fb609712949dc8783f4cae4806acd9a73da6ff + languageName: node + linkType: hard + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 845bd280c55a6a91d232cfa54eaf9708ec71e594676fe705794f494bb8b711d833b752b59d1a5c154695225880c23dbc9cab0e53af16fd57807976cd3ff41b8d + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.18.9": + version: 7.20.7 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.20.7" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 + "@babel/plugin-proposal-optional-chaining": ^7.20.7 + peerDependencies: + "@babel/core": ^7.13.0 + checksum: d610f532210bee5342f5b44a12395ccc6d904e675a297189bc1e401cc185beec09873da523466d7fec34ae1574f7a384235cba1ccc9fe7b89ba094167897c845 + languageName: node + linkType: hard + +"@babel/plugin-proposal-async-generator-functions@npm:^7.20.1": + version: 7.20.7 + resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.20.7" + dependencies: + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-remap-async-to-generator": ^7.18.9 + "@babel/plugin-syntax-async-generators": ^7.8.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 111109ee118c9e69982f08d5e119eab04190b36a0f40e22e873802d941956eee66d2aa5a15f5321e51e3f9aa70a91136451b987fe15185ef8cc547ac88937723 + languageName: node + linkType: hard + +"@babel/plugin-proposal-class-properties@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 + languageName: node + linkType: hard + +"@babel/plugin-proposal-class-static-block@npm:^7.18.6": + version: 7.21.0 + resolution: "@babel/plugin-proposal-class-static-block@npm:7.21.0" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.21.0 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + peerDependencies: + "@babel/core": ^7.12.0 + checksum: 236c0ad089e7a7acab776cc1d355330193314bfcd62e94e78f2df35817c6144d7e0e0368976778afd6b7c13e70b5068fa84d7abbf967d4f182e60d03f9ef802b + languageName: node + linkType: hard + +"@babel/plugin-proposal-dynamic-import@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-dynamic-import@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 96b1c8a8ad8171d39e9ab106be33bde37ae09b22fb2c449afee9a5edf3c537933d79d963dcdc2694d10677cb96da739cdf1b53454e6a5deab9801f28a818bb2f + languageName: node + linkType: hard + +"@babel/plugin-proposal-export-namespace-from@npm:^7.18.9": + version: 7.18.9 + resolution: "@babel/plugin-proposal-export-namespace-from@npm:7.18.9" + dependencies: + "@babel/helper-plugin-utils": ^7.18.9 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 84ff22bacc5d30918a849bfb7e0e90ae4c5b8d8b65f2ac881803d1cf9068dffbe53bd657b0e4bc4c20b4db301b1c85f1e74183cf29a0dd31e964bd4e97c363ef + languageName: node + linkType: hard + +"@babel/plugin-proposal-json-strings@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-json-strings@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + "@babel/plugin-syntax-json-strings": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 25ba0e6b9d6115174f51f7c6787e96214c90dd4026e266976b248a2ed417fe50fddae72843ffb3cbe324014a18632ce5648dfac77f089da858022b49fd608cb3 + languageName: node + linkType: hard + +"@babel/plugin-proposal-logical-assignment-operators@npm:^7.18.9": + version: 7.20.7 + resolution: "@babel/plugin-proposal-logical-assignment-operators@npm:7.20.7" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cdd7b8136cc4db3f47714d5266f9e7b592a2ac5a94a5878787ce08890e97c8ab1ca8e94b27bfeba7b0f2b1549a026d9fc414ca2196de603df36fb32633bbdc19 + languageName: node + linkType: hard + +"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 949c9ddcdecdaec766ee610ef98f965f928ccc0361dd87cf9f88cf4896a6ccd62fce063d4494778e50da99dea63d270a1be574a62d6ab81cbe9d85884bf55a7d + languageName: node + linkType: hard + +"@babel/plugin-proposal-numeric-separator@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-numeric-separator@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f370ea584c55bf4040e1f78c80b4eeb1ce2e6aaa74f87d1a48266493c33931d0b6222d8cee3a082383d6bb648ab8d6b7147a06f974d3296ef3bc39c7851683ec + languageName: node + linkType: hard + +"@babel/plugin-proposal-object-rest-spread@npm:^7.20.2": + version: 7.20.7 + resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.20.7" + dependencies: + "@babel/compat-data": ^7.20.5 + "@babel/helper-compilation-targets": ^7.20.7 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-transform-parameters": ^7.20.7 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1329db17009964bc644484c660eab717cb3ca63ac0ab0f67c651a028d1bc2ead51dc4064caea283e46994f1b7221670a35cbc0b4beb6273f55e915494b5aa0b2 + languageName: node + linkType: hard + +"@babel/plugin-proposal-optional-catch-binding@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-optional-catch-binding@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7b5b39fb5d8d6d14faad6cb68ece5eeb2fd550fb66b5af7d7582402f974f5bc3684641f7c192a5a57e0f59acfae4aada6786be1eba030881ddc590666eff4d1e + languageName: node + linkType: hard + +"@babel/plugin-proposal-optional-chaining@npm:^7.18.9, @babel/plugin-proposal-optional-chaining@npm:^7.20.7": + version: 7.21.0 + resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 11c5449e01b18bb8881e8e005a577fa7be2fe5688e2382c8822d51f8f7005342a301a46af7b273b1f5645f9a7b894c428eee8526342038a275ef6ba4c8d8d746 + languageName: node + linkType: hard + +"@babel/plugin-proposal-private-methods@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-private-methods@npm:7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 22d8502ee96bca99ad2c8393e8493e2b8d4507576dd054490fd8201a36824373440106f5b098b6d821b026c7e72b0424ff4aeca69ed5f42e48f029d3a156d5ad + languageName: node + linkType: hard + +"@babel/plugin-proposal-private-property-in-object@npm:^7.18.6": + version: 7.21.0 + resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + "@babel/helper-create-class-features-plugin": ^7.21.0 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: add881a6a836635c41d2710551fdf777e2c07c0b691bf2baacc5d658dd64107479df1038680d6e67c468bfc6f36fb8920025d6bac2a1df0a81b867537d40ae78 + languageName: node + linkType: hard + +"@babel/plugin-proposal-unicode-property-regex@npm:^7.18.6, @babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": + version: 7.18.6 + resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a8575ecb7ff24bf6c6e94808d5c84bb5a0c6dd7892b54f09f4646711ba0ee1e1668032b3c43e3e1dfec2c5716c302e851ac756c1645e15882d73df6ad21ae951 + languageName: node + linkType: hard + +"@babel/plugin-syntax-async-generators@npm:^7.8.4": + version: 7.8.4 + resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 + languageName: node + linkType: hard + +"@babel/plugin-syntax-bigint@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-bigint@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3a10849d83e47aec50f367a9e56a6b22d662ddce643334b087f9828f4c3dd73bdc5909aaeabe123fed78515767f9ca43498a0e621c438d1cd2802d7fae3c9648 + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-properties@npm:^7.12.13, @babel/plugin-syntax-class-properties@npm:^7.8.3": + version: 7.12.13 + resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" + dependencies: + "@babel/helper-plugin-utils": ^7.12.13 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-static-block@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 + languageName: node + linkType: hard + +"@babel/plugin-syntax-dynamic-import@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ce307af83cf433d4ec42932329fad25fa73138ab39c7436882ea28742e1c0066626d224e0ad2988724c82644e41601cef607b36194f695cb78a1fcdc959637bd + languageName: node + linkType: hard + +"@babel/plugin-syntax-export-namespace-from@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-export-namespace-from@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 85740478be5b0de185228e7814451d74ab8ce0a26fcca7613955262a26e99e8e15e9da58f60c754b84515d4c679b590dbd3f2148f0f58025f4ae706f1c5a5d4a + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-assertions@npm:^7.20.0": + version: 7.20.0 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.20.0" + dependencies: + "@babel/helper-plugin-utils": ^7.19.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6a86220e0aae40164cd3ffaf80e7c076a1be02a8f3480455dddbae05fda8140f429290027604df7a11b3f3f124866e8a6d69dbfa1dda61ee7377b920ad144d5b + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-meta@npm:^7.8.3": + version: 7.10.4 + resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b + languageName: node + linkType: hard + +"@babel/plugin-syntax-json-strings@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:^7.7.2": + version: 7.18.6 + resolution: "@babel/plugin-syntax-jsx@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6d37ea972970195f1ffe1a54745ce2ae456e0ac6145fae9aa1480f297248b262ea6ebb93010eddb86ebfacb94f57c05a1fc5d232b9a67325b09060299d515c67 + languageName: node + linkType: hard + +"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4, @babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": + version: 7.10.4 + resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: aff33577037e34e515911255cdbb1fd39efee33658aa00b8a5fd3a4b903585112d037cce1cc9e4632f0487dc554486106b79ccd5ea63a2e00df4363f6d4ff886 + languageName: node + linkType: hard + +"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-numeric-separator@npm:^7.10.4, @babel/plugin-syntax-numeric-separator@npm:^7.8.3": + version: 7.10.4 + resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-object-rest-spread@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-chaining@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 + languageName: node + linkType: hard + +"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda + languageName: node + linkType: hard + +"@babel/plugin-syntax-top-level-await@npm:^7.14.5, @babel/plugin-syntax-top-level-await@npm:^7.8.3": + version: 7.14.5 + resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e + languageName: node + linkType: hard + +"@babel/plugin-syntax-typescript@npm:^7.7.2": + version: 7.20.0 + resolution: "@babel/plugin-syntax-typescript@npm:7.20.0" + dependencies: + "@babel/helper-plugin-utils": ^7.19.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6189c0b5c32ba3c9a80a42338bd50719d783b20ef29b853d4f03929e971913d3cefd80184e924ae98ad6db09080be8fe6f1ffde9a6db8972523234f0274d36f7 + languageName: node + linkType: hard + +"@babel/plugin-transform-arrow-functions@npm:^7.18.6": + version: 7.20.7 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.20.7" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b43cabe3790c2de7710abe32df9a30005eddb2050dadd5d122c6872f679e5710e410f1b90c8f99a2aff7b614cccfecf30e7fd310236686f60d3ed43fd80b9847 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-to-generator@npm:^7.18.6": + version: 7.20.7 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.20.7" + dependencies: + "@babel/helper-module-imports": ^7.18.6 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-remap-async-to-generator": ^7.18.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: fe9ee8a5471b4317c1b9ea92410ace8126b52a600d7cfbfe1920dcac6fb0fad647d2e08beb4fd03c630eb54430e6c72db11e283e3eddc49615c68abd39430904 + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoped-functions@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0a0df61f94601e3666bf39f2cc26f5f7b22a94450fb93081edbed967bd752ce3f81d1227fefd3799f5ee2722171b5e28db61379234d1bb85b6ec689589f99d7e + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoping@npm:^7.20.2": + version: 7.21.0 + resolution: "@babel/plugin-transform-block-scoping@npm:7.21.0" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 15aacaadbecf96b53a750db1be4990b0d89c7f5bc3e1794b63b49fb219638c1fd25d452d15566d7e5ddf5b5f4e1a0a0055c35c1c7aee323c7b114bf49f66f4b0 + languageName: node + linkType: hard + +"@babel/plugin-transform-classes@npm:^7.20.2": + version: 7.21.0 + resolution: "@babel/plugin-transform-classes@npm:7.21.0" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + "@babel/helper-compilation-targets": ^7.20.7 + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-function-name": ^7.21.0 + "@babel/helper-optimise-call-expression": ^7.18.6 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-replace-supers": ^7.20.7 + "@babel/helper-split-export-declaration": ^7.18.6 + globals: ^11.1.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 088ae152074bd0e90f64659169255bfe50393e637ec8765cb2a518848b11b0299e66b91003728fd0a41563a6fdc6b8d548ece698a314fd5447f5489c22e466b7 + languageName: node + linkType: hard + +"@babel/plugin-transform-computed-properties@npm:^7.18.9": + version: 7.20.7 + resolution: "@babel/plugin-transform-computed-properties@npm:7.20.7" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/template": ^7.20.7 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: be70e54bda8b469146459f429e5f2bd415023b87b2d5af8b10e48f465ffb02847a3ed162ca60378c004b82db848e4d62e90010d41ded7e7176b6d8d1c2911139 + languageName: node + linkType: hard + +"@babel/plugin-transform-destructuring@npm:^7.20.2": + version: 7.20.7 + resolution: "@babel/plugin-transform-destructuring@npm:7.20.7" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bd8affdb142c77662037215e37128b2110a786c92a67e1f00b38223c438c1610bd84cbc0386e9cd3479245ea811c5ca6c9838f49be4729b592159a30ce79add2 + languageName: node + linkType: hard + +"@babel/plugin-transform-dotall-regex@npm:^7.18.6, @babel/plugin-transform-dotall-regex@npm:^7.4.4": + version: 7.18.6 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cbe5d7063eb8f8cca24cd4827bc97f5641166509e58781a5f8aa47fb3d2d786ce4506a30fca2e01f61f18792783a5cb5d96bf5434c3dd1ad0de8c9cc625a53da + languageName: node + linkType: hard + +"@babel/plugin-transform-duplicate-keys@npm:^7.18.9": + version: 7.18.9 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.18.9" + dependencies: + "@babel/helper-plugin-utils": ^7.18.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 220bf4a9fec5c4d4a7b1de38810350260e8ea08481bf78332a464a21256a95f0df8cd56025f346238f09b04f8e86d4158fafc9f4af57abaef31637e3b58bd4fe + languageName: node + linkType: hard + +"@babel/plugin-transform-exponentiation-operator@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.18.6" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7f70222f6829c82a36005508d34ddbe6fd0974ae190683a8670dd6ff08669aaf51fef2209d7403f9bd543cb2d12b18458016c99a6ed0332ccedb3ea127b01229 + languageName: node + linkType: hard + +"@babel/plugin-transform-for-of@npm:^7.18.8": + version: 7.21.0 + resolution: "@babel/plugin-transform-for-of@npm:7.21.0" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2f3f86ca1fab2929fcda6a87e4303d5c635b5f96dc9a45fd4ca083308a3020c79ac33b9543eb4640ef2b79f3586a00ab2d002a7081adb9e9d7440dce30781034 + languageName: node + linkType: hard + +"@babel/plugin-transform-function-name@npm:^7.18.9": + version: 7.18.9 + resolution: "@babel/plugin-transform-function-name@npm:7.18.9" + dependencies: + "@babel/helper-compilation-targets": ^7.18.9 + "@babel/helper-function-name": ^7.18.9 + "@babel/helper-plugin-utils": ^7.18.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 62dd9c6cdc9714704efe15545e782ee52d74dc73916bf954b4d3bee088fb0ec9e3c8f52e751252433656c09f744b27b757fc06ed99bcde28e8a21600a1d8e597 + languageName: node + linkType: hard + +"@babel/plugin-transform-literals@npm:^7.18.9": + version: 7.18.9 + resolution: "@babel/plugin-transform-literals@npm:7.18.9" + dependencies: + "@babel/helper-plugin-utils": ^7.18.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3458dd2f1a47ac51d9d607aa18f3d321cbfa8560a985199185bed5a906bb0c61ba85575d386460bac9aed43fdd98940041fae5a67dff286f6f967707cff489f8 + languageName: node + linkType: hard + +"@babel/plugin-transform-member-expression-literals@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 35a3d04f6693bc6b298c05453d85ee6e41cc806538acb6928427e0e97ae06059f97d2f07d21495fcf5f70d3c13a242e2ecbd09d5c1fcb1b1a73ff528dcb0b695 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-amd@npm:^7.19.6": + version: 7.20.11 + resolution: "@babel/plugin-transform-modules-amd@npm:7.20.11" + dependencies: + "@babel/helper-module-transforms": ^7.20.11 + "@babel/helper-plugin-utils": ^7.20.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 23665c1c20c8f11c89382b588fb9651c0756d130737a7625baeaadbd3b973bc5bfba1303bedffa8fb99db1e6d848afb01016e1df2b69b18303e946890c790001 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.19.6": + version: 7.21.2 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.21.2" + dependencies: + "@babel/helper-module-transforms": ^7.21.2 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-simple-access": ^7.20.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 65aa06e3e3792f39b99eb5f807034693ff0ecf80438580f7ae504f4c4448ef04147b1889ea5e6f60f3ad4a12ebbb57c6f1f979a249dadbd8d11fe22f4441918b + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-systemjs@npm:^7.19.6": + version: 7.20.11 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.20.11" + dependencies: + "@babel/helper-hoist-variables": ^7.18.6 + "@babel/helper-module-transforms": ^7.20.11 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-validator-identifier": ^7.19.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4546c47587f88156d66c7eb7808e903cf4bb3f6ba6ac9bc8e3af2e29e92eb9f0b3f44d52043bfd24eb25fa7827fd7b6c8bfeac0cac7584e019b87e1ecbd0e673 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-umd@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-modules-umd@npm:7.18.6" + dependencies: + "@babel/helper-module-transforms": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c3b6796c6f4579f1ba5ab0cdcc73910c1e9c8e1e773c507c8bb4da33072b3ae5df73c6d68f9126dab6e99c24ea8571e1563f8710d7c421fac1cde1e434c20153 + languageName: node + linkType: hard + +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.19.1": + version: 7.20.5 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.20.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.20.5 + "@babel/helper-plugin-utils": ^7.20.2 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 528c95fb1087e212f17e1c6456df041b28a83c772b9c93d2e407c9d03b72182b0d9d126770c1d6e0b23aab052599ceaf25ed6a2c0627f4249be34a83f6fae853 + languageName: node + linkType: hard + +"@babel/plugin-transform-new-target@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-new-target@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bd780e14f46af55d0ae8503b3cb81ca86dcc73ed782f177e74f498fff934754f9e9911df1f8f3bd123777eed7c1c1af4d66abab87c8daae5403e7719a6b845d1 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-object-super@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + "@babel/helper-replace-supers": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0fcb04e15deea96ae047c21cb403607d49f06b23b4589055993365ebd7a7d7541334f06bf9642e90075e66efce6ebaf1eb0ef066fbbab802d21d714f1aac3aef + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.20.1, @babel/plugin-transform-parameters@npm:^7.20.7": + version: 7.20.7 + resolution: "@babel/plugin-transform-parameters@npm:7.20.7" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6ffe0dd9afb2d2b9bc247381aa2e95dd9997ff5568a0a11900528919a4e073ac68f46409431455badb8809644d47cff180045bc2b9700e3f36e3b23554978947 + languageName: node + linkType: hard + +"@babel/plugin-transform-property-literals@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-property-literals@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1c16e64de554703f4b547541de2edda6c01346dd3031d4d29e881aa7733785cd26d53611a4ccf5353f4d3e69097bb0111c0a93ace9e683edd94fea28c4484144 + languageName: node + linkType: hard + +"@babel/plugin-transform-regenerator@npm:^7.18.6": + version: 7.20.5 + resolution: "@babel/plugin-transform-regenerator@npm:7.20.5" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + regenerator-transform: ^0.15.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 13164861e71fb23d84c6270ef5330b03c54d5d661c2c7468f28e21c4f8598558ca0c8c3cb1d996219352946e849d270a61372bc93c8fbe9676e78e3ffd0dea07 + languageName: node + linkType: hard + +"@babel/plugin-transform-reserved-words@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-reserved-words@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0738cdc30abdae07c8ec4b233b30c31f68b3ff0eaa40eddb45ae607c066127f5fa99ddad3c0177d8e2832e3a7d3ad115775c62b431ebd6189c40a951b867a80c + languageName: node + linkType: hard + +"@babel/plugin-transform-shorthand-properties@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b8e4e8acc2700d1e0d7d5dbfd4fdfb935651913de6be36e6afb7e739d8f9ca539a5150075a0f9b79c88be25ddf45abb912fe7abf525f0b80f5b9d9860de685d7 + languageName: node + linkType: hard + +"@babel/plugin-transform-spread@npm:^7.19.0": + version: 7.20.7 + resolution: "@babel/plugin-transform-spread@npm:7.20.7" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8ea698a12da15718aac7489d4cde10beb8a3eea1f66167d11ab1e625033641e8b328157fd1a0b55dd6531933a160c01fc2e2e61132a385cece05f26429fd0cc2 + languageName: node + linkType: hard + +"@babel/plugin-transform-sticky-regex@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 68ea18884ae9723443ffa975eb736c8c0d751265859cd3955691253f7fee37d7a0f7efea96c8a062876af49a257a18ea0ed5fea0d95a7b3611ce40f7ee23aee3 + languageName: node + linkType: hard + +"@babel/plugin-transform-template-literals@npm:^7.18.9": + version: 7.18.9 + resolution: "@babel/plugin-transform-template-literals@npm:7.18.9" + dependencies: + "@babel/helper-plugin-utils": ^7.18.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3d2fcd79b7c345917f69b92a85bdc3ddd68ce2c87dc70c7d61a8373546ccd1f5cb8adc8540b49dfba08e1b82bb7b3bbe23a19efdb2b9c994db2db42906ca9fb2 + languageName: node + linkType: hard + +"@babel/plugin-transform-typeof-symbol@npm:^7.18.9": + version: 7.18.9 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.18.9" + dependencies: + "@babel/helper-plugin-utils": ^7.18.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e754e0d8b8a028c52e10c148088606e3f7a9942c57bd648fc0438e5b4868db73c386a5ed47ab6d6f0594aae29ee5ffc2ffc0f7ebee7fae560a066d6dea811cd4 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-escapes@npm:^7.18.10": + version: 7.18.10 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.18.10" + dependencies: + "@babel/helper-plugin-utils": ^7.18.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f5baca55cb3c11bc08ec589f5f522d85c1ab509b4d11492437e45027d64ae0b22f0907bd1381e8d7f2a436384bb1f9ad89d19277314242c5c2671a0f91d0f9cd + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-regex@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d9e18d57536a2d317fb0b7c04f8f55347f3cfacb75e636b4c6fa2080ab13a3542771b5120e726b598b815891fc606d1472ac02b749c69fd527b03847f22dc25e + languageName: node + linkType: hard + +"@babel/preset-env@npm:^7.10.2": + version: 7.20.2 + resolution: "@babel/preset-env@npm:7.20.2" + dependencies: + "@babel/compat-data": ^7.20.1 + "@babel/helper-compilation-targets": ^7.20.0 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-validator-option": ^7.18.6 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.18.6 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.18.9 + "@babel/plugin-proposal-async-generator-functions": ^7.20.1 + "@babel/plugin-proposal-class-properties": ^7.18.6 + "@babel/plugin-proposal-class-static-block": ^7.18.6 + "@babel/plugin-proposal-dynamic-import": ^7.18.6 + "@babel/plugin-proposal-export-namespace-from": ^7.18.9 + "@babel/plugin-proposal-json-strings": ^7.18.6 + "@babel/plugin-proposal-logical-assignment-operators": ^7.18.9 + "@babel/plugin-proposal-nullish-coalescing-operator": ^7.18.6 + "@babel/plugin-proposal-numeric-separator": ^7.18.6 + "@babel/plugin-proposal-object-rest-spread": ^7.20.2 + "@babel/plugin-proposal-optional-catch-binding": ^7.18.6 + "@babel/plugin-proposal-optional-chaining": ^7.18.9 + "@babel/plugin-proposal-private-methods": ^7.18.6 + "@babel/plugin-proposal-private-property-in-object": ^7.18.6 + "@babel/plugin-proposal-unicode-property-regex": ^7.18.6 + "@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-import-assertions": ^7.20.0 + "@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.18.6 + "@babel/plugin-transform-async-to-generator": ^7.18.6 + "@babel/plugin-transform-block-scoped-functions": ^7.18.6 + "@babel/plugin-transform-block-scoping": ^7.20.2 + "@babel/plugin-transform-classes": ^7.20.2 + "@babel/plugin-transform-computed-properties": ^7.18.9 + "@babel/plugin-transform-destructuring": ^7.20.2 + "@babel/plugin-transform-dotall-regex": ^7.18.6 + "@babel/plugin-transform-duplicate-keys": ^7.18.9 + "@babel/plugin-transform-exponentiation-operator": ^7.18.6 + "@babel/plugin-transform-for-of": ^7.18.8 + "@babel/plugin-transform-function-name": ^7.18.9 + "@babel/plugin-transform-literals": ^7.18.9 + "@babel/plugin-transform-member-expression-literals": ^7.18.6 + "@babel/plugin-transform-modules-amd": ^7.19.6 + "@babel/plugin-transform-modules-commonjs": ^7.19.6 + "@babel/plugin-transform-modules-systemjs": ^7.19.6 + "@babel/plugin-transform-modules-umd": ^7.18.6 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.19.1 + "@babel/plugin-transform-new-target": ^7.18.6 + "@babel/plugin-transform-object-super": ^7.18.6 + "@babel/plugin-transform-parameters": ^7.20.1 + "@babel/plugin-transform-property-literals": ^7.18.6 + "@babel/plugin-transform-regenerator": ^7.18.6 + "@babel/plugin-transform-reserved-words": ^7.18.6 + "@babel/plugin-transform-shorthand-properties": ^7.18.6 + "@babel/plugin-transform-spread": ^7.19.0 + "@babel/plugin-transform-sticky-regex": ^7.18.6 + "@babel/plugin-transform-template-literals": ^7.18.9 + "@babel/plugin-transform-typeof-symbol": ^7.18.9 + "@babel/plugin-transform-unicode-escapes": ^7.18.10 + "@babel/plugin-transform-unicode-regex": ^7.18.6 + "@babel/preset-modules": ^0.1.5 + "@babel/types": ^7.20.2 + babel-plugin-polyfill-corejs2: ^0.3.3 + babel-plugin-polyfill-corejs3: ^0.6.0 + babel-plugin-polyfill-regenerator: ^0.4.1 + core-js-compat: ^3.25.1 + semver: ^6.3.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ece2d7e9c7789db6116e962b8e1a55eb55c110c44c217f0c8f6ffea4ca234954e66557f7bd019b7affadf7fbb3a53ccc807e93fc935aacd48146234b73b6947e + languageName: node + linkType: hard + +"@babel/preset-modules@npm:^0.1.5": + version: 0.1.5 + resolution: "@babel/preset-modules@npm:0.1.5" + 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 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8430e0e9e9d520b53e22e8c4c6a5a080a12b63af6eabe559c2310b187bd62ae113f3da82ba33e9d1d0f3230930ca702843aae9dd226dec51f7d7114dc1f51c10 + languageName: node + linkType: hard + +"@babel/regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "@babel/regjsgen@npm:0.8.0" + checksum: 89c338fee774770e5a487382170711014d49a68eb281e74f2b5eac88f38300a4ad545516a7786a8dd5702e9cf009c94c2f582d200f077ac5decd74c56b973730 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.8.4": + version: 7.21.0 + resolution: "@babel/runtime@npm:7.21.0" + dependencies: + regenerator-runtime: ^0.13.11 + checksum: 7b33e25bfa9e0e1b9e8828bb61b2d32bdd46b41b07ba7cb43319ad08efc6fda8eb89445193e67d6541814627df0ca59122c0ea795e412b99c5183a0540d338ab + languageName: node + linkType: hard + +"@babel/template@npm:^7.18.10, @babel/template@npm:^7.20.7, @babel/template@npm:^7.3.3": + version: 7.20.7 + resolution: "@babel/template@npm:7.20.7" + dependencies: + "@babel/code-frame": ^7.18.6 + "@babel/parser": ^7.20.7 + "@babel/types": ^7.20.7 + checksum: 2eb1a0ab8d415078776bceb3473d07ab746e6bb4c2f6ca46ee70efb284d75c4a32bb0cd6f4f4946dec9711f9c0780e8e5d64b743208deac6f8e9858afadc349e + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.20.5, @babel/traverse@npm:^7.20.7, @babel/traverse@npm:^7.21.0, @babel/traverse@npm:^7.21.2, @babel/traverse@npm:^7.7.2": + version: 7.21.2 + resolution: "@babel/traverse@npm:7.21.2" + dependencies: + "@babel/code-frame": ^7.18.6 + "@babel/generator": ^7.21.1 + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-function-name": ^7.21.0 + "@babel/helper-hoist-variables": ^7.18.6 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/parser": ^7.21.2 + "@babel/types": ^7.21.2 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: d851e3f5cfbdc2fac037a014eae7b0707709de50f7d2fbb82ffbf932d3eeba90a77431529371d6e544f8faaf8c6540eeb18fdd8d1c6fa2b61acea0fb47e18d4b + languageName: node + linkType: hard + +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.5, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.2, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.21.2 + resolution: "@babel/types@npm:7.21.2" + dependencies: + "@babel/helper-string-parser": ^7.19.4 + "@babel/helper-validator-identifier": ^7.19.1 + to-fast-properties: ^2.0.0 + checksum: a45a52acde139e575502c6de42c994bdbe262bafcb92ae9381fb54cdf1a3672149086843fda655c7683ce9806e998fd002bbe878fa44984498d0fdc7935ce7ff + languageName: node + linkType: hard + +"@bcoe/v8-coverage@npm:^0.2.3": + version: 0.2.3 + resolution: "@bcoe/v8-coverage@npm:0.2.3" + checksum: 850f9305536d0f2bd13e9e0881cb5f02e4f93fad1189f7b2d4bebf694e3206924eadee1068130d43c11b750efcc9405f88a8e42ef098b6d75239c0f047de1a27 + languageName: node + linkType: hard + +"@chevrotain/types@npm:^9.1.0": + version: 9.1.0 + resolution: "@chevrotain/types@npm:9.1.0" + checksum: 5f26ff26aa345bc823b39ebe48f038db0998c80d13fa4b937961d68523a259ac86ec693bc1ad3f3cfa9ef83e5ffb6d94337960c3a1ee7cb82e3014adb4f5bf30 + languageName: node + linkType: hard + +"@chevrotain/utils@npm:^9.1.0": + version: 9.1.0 + resolution: "@chevrotain/utils@npm:9.1.0" + checksum: ca78c97c7c3e444431d0fafa348f0c955998cd86bc0d4bbdeaae3ff5abba8d416d69d5a4163e86cac962a392f1c325cb4a97b8b05722527da62e9b7635025e02 + languageName: node + linkType: hard + +"@codemirror/autocomplete@npm:^6.0.0, @codemirror/autocomplete@npm:^6.3.2, @codemirror/autocomplete@npm:^6.5.1": + version: 6.5.1 + resolution: "@codemirror/autocomplete@npm:6.5.1" + dependencies: + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.6.0 + "@lezer/common": ^1.0.0 + peerDependencies: + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + "@lezer/common": ^1.0.0 + checksum: c7026af557f5e467050bea22b3e9b060adca065fc84c22f024fd59730107ea711006dd353050300acce5862cfb82643fb3edbdef80c8b275214398147395e6da + languageName: node + linkType: hard + +"@codemirror/commands@npm:^6.2.3": + version: 6.2.3 + resolution: "@codemirror/commands@npm:6.2.3" + dependencies: + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.2.0 + "@codemirror/view": ^6.0.0 + "@lezer/common": ^1.0.0 + checksum: e6b7d07818d6df4372a272539b84a256e651cfa3416a33f9e1859f2ced0f6e3c944e0c40c2c407dcd5b13ffab2931d4e5ea5952db439837071de336e7a31c722 + languageName: node + linkType: hard + +"@codemirror/lang-cpp@npm:^6.0.2": + version: 6.0.2 + resolution: "@codemirror/lang-cpp@npm:6.0.2" + dependencies: + "@codemirror/language": ^6.0.0 + "@lezer/cpp": ^1.0.0 + checksum: bb9eba482cca80037ce30c7b193cf45eff19ccbb773764fddf2071756468ecc25aa53c777c943635054f89095b0247b9b50c339e107e41e68d34d12a7295f9a9 + languageName: node + linkType: hard + +"@codemirror/lang-css@npm:^6.0.0, @codemirror/lang-css@npm:^6.1.1": + version: 6.1.1 + resolution: "@codemirror/lang-css@npm:6.1.1" + dependencies: + "@codemirror/autocomplete": ^6.0.0 + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@lezer/css": ^1.0.0 + checksum: 9b0bf7c7544fb604b67325689d783981e4099560f577bc1f10c52cb18e9d275ebdbdbd3f335a1dbb9c4910c36320f74ca015fc92ef99f930ecb9d481a2bf3511 + languageName: node + linkType: hard + +"@codemirror/lang-html@npm:^6.0.0, @codemirror/lang-html@npm:^6.4.3": + version: 6.4.3 + resolution: "@codemirror/lang-html@npm:6.4.3" + dependencies: + "@codemirror/autocomplete": ^6.0.0 + "@codemirror/lang-css": ^6.0.0 + "@codemirror/lang-javascript": ^6.0.0 + "@codemirror/language": ^6.4.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.2.2 + "@lezer/common": ^1.0.0 + "@lezer/css": ^1.1.0 + "@lezer/html": ^1.3.0 + checksum: 6177d19147580964ecd6910ae951201929a96e63f4f0e624c3138e2805fa87ec6d6d952a3a888c5a52af78b6dd6d04d7d8c76c6a9cd65b1921dc467b5dbaea72 + languageName: node + linkType: hard + +"@codemirror/lang-java@npm:^6.0.1": + version: 6.0.1 + resolution: "@codemirror/lang-java@npm:6.0.1" + dependencies: + "@codemirror/language": ^6.0.0 + "@lezer/java": ^1.0.0 + checksum: 4679104683cbffcd224ac04c7e5d144b787494697b26470b07017259035b7bb3fa62609d9a61bfbc566f1756d9f972f9f26d96a3c1362dd48881c1172f9a914d + languageName: node + linkType: hard + +"@codemirror/lang-javascript@npm:^6.0.0, @codemirror/lang-javascript@npm:^6.1.7": + version: 6.1.7 + resolution: "@codemirror/lang-javascript@npm:6.1.7" + dependencies: + "@codemirror/autocomplete": ^6.0.0 + "@codemirror/language": ^6.6.0 + "@codemirror/lint": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + "@lezer/common": ^1.0.0 + "@lezer/javascript": ^1.0.0 + checksum: 15ce6695e7276102dbc874d178cbc4434d126b7a3e08f89aa9338c7dce5d2d6bdd5f1c6d114a744a8fa26dfc62b0dc639fe6e5c7b306bd14ed37272e75739736 + languageName: node + linkType: hard + +"@codemirror/lang-json@npm:^6.0.1": + version: 6.0.1 + resolution: "@codemirror/lang-json@npm:6.0.1" + dependencies: + "@codemirror/language": ^6.0.0 + "@lezer/json": ^1.0.0 + checksum: e9e87d50ff7b81bd56a6ab50740b1dd54e9a93f1be585e1d59d0642e2148842ea1528ac7b7221eb4ddc7fe84bbc28065144cc3ab86f6e06c6aeb2d4b4e62acf1 + languageName: node + linkType: hard + +"@codemirror/lang-markdown@npm:^6.1.1": + version: 6.1.1 + resolution: "@codemirror/lang-markdown@npm:6.1.1" + dependencies: + "@codemirror/lang-html": ^6.0.0 + "@codemirror/language": ^6.3.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + "@lezer/common": ^1.0.0 + "@lezer/markdown": ^1.0.0 + checksum: db891dad10a8ea8db17d0a9222774389794cb0957b784e3f154bf27ab4a9be89a28ad4c2f6abf7d829115c3ce46694a2816b61723a5d5776c1d75d566ce016c8 + languageName: node + linkType: hard + +"@codemirror/lang-php@npm:^6.0.1": + version: 6.0.1 + resolution: "@codemirror/lang-php@npm:6.0.1" + dependencies: + "@codemirror/lang-html": ^6.0.0 + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@lezer/common": ^1.0.0 + "@lezer/php": ^1.0.0 + checksum: c003a29a426486453fdfddbf7302982fa2aa7f059bf6f1ce4cbf08341b0162eee5e2f50e0d71c418dcd358491631780156d846fe352754d042576172c5d86721 + languageName: node + linkType: hard + +"@codemirror/lang-python@npm:^6.1.3": + version: 6.1.3 + resolution: "@codemirror/lang-python@npm:6.1.3" + dependencies: + "@codemirror/autocomplete": ^6.3.2 + "@codemirror/language": ^6.8.0 + "@lezer/python": ^1.1.4 + checksum: 65a0276a4503e4e3b70dd28d1c93ef472632b6d2c4bf3ae92d305d14ee8cf60b0bbbf62d5ceb51294de9598d9e2d42eafcde26f317ee7b90d0a11dfa863c1d1a + languageName: node + linkType: hard + +"@codemirror/lang-rust@npm:^6.0.1": + version: 6.0.1 + resolution: "@codemirror/lang-rust@npm:6.0.1" + dependencies: + "@codemirror/language": ^6.0.0 + "@lezer/rust": ^1.0.0 + checksum: 8a439944cb22159b0b3465ca4fa4294c69843219d5d30e278ae6df8e48f30a7a9256129723c025ec9b5e694d31a3560fb004300b125ffcd81c22d13825845170 + languageName: node + linkType: hard + +"@codemirror/lang-sql@npm:^6.4.1": + version: 6.4.1 + resolution: "@codemirror/lang-sql@npm:6.4.1" + dependencies: + "@codemirror/autocomplete": ^6.0.0 + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: d1823e760b88bb15399684b1136b3c7167f104854645b971aa80d7e261e4ad204a5258f1ccd9bbb37a90b20821d2b8fcfac9092198e599b21e7a0cb1e50dc0ee + languageName: node + linkType: hard + +"@codemirror/lang-wast@npm:^6.0.1": + version: 6.0.1 + resolution: "@codemirror/lang-wast@npm:6.0.1" + dependencies: + "@codemirror/language": ^6.0.0 + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 600d98d3ea6a4e99292244ed707e39a2abd9f3abf62cfeff5c819a0cc0c7e86b8c5b91e91c1b7ea21233d9ea09c41abe61d8a40b2547bb5db74239c6df857934 + languageName: node + linkType: hard + +"@codemirror/lang-xml@npm:^6.0.2": + version: 6.0.2 + resolution: "@codemirror/lang-xml@npm:6.0.2" + dependencies: + "@codemirror/autocomplete": ^6.0.0 + "@codemirror/language": ^6.4.0 + "@codemirror/state": ^6.0.0 + "@lezer/common": ^1.0.0 + "@lezer/xml": ^1.0.0 + checksum: e156ecafaa87e9b6ef4ab6812ccd00d8f3c6cb81f232837636b36336d80513b61936dfee6f4f6800574f236208b61e95a2abcb997cdcd7366585a6b796e0e13b + languageName: node + linkType: hard + +"@codemirror/language@npm:^6.0.0, @codemirror/language@npm:^6.3.0, @codemirror/language@npm:^6.4.0, @codemirror/language@npm:^6.6.0, @codemirror/language@npm:^6.8.0": + version: 6.8.0 + resolution: "@codemirror/language@npm:6.8.0" + dependencies: + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + "@lezer/common": ^1.0.0 + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + style-mod: ^4.0.0 + checksum: 64408d996641931fa4c6b892e17ee1fdaee0f63d3d84c019a6ea7b1e6d1c774f92357b95c2ebaed60545062b795b72d0a058c03578b2bf4023c87726e97b5d2f + languageName: node + linkType: hard + +"@codemirror/legacy-modes@npm:^6.3.2": + version: 6.3.2 + resolution: "@codemirror/legacy-modes@npm:6.3.2" + dependencies: + "@codemirror/language": ^6.0.0 + checksum: fa5f5477fb9e19267251e2ecd3de8c1a4c2512813555bb60111dce3951f2c3f6080a2985a573b7542534ba1d2c34115f7e39ee23fdf8f6f81db6f8ce447c1efc + languageName: node + linkType: hard + +"@codemirror/lint@npm:^6.0.0": + version: 6.2.0 + resolution: "@codemirror/lint@npm:6.2.0" + dependencies: + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + crelt: ^1.0.5 + checksum: b97e55a07bca9f7e357e495853ba189ae0ff7dfe7e7ae445d7a0d6c6926ec792c7f5c6b6c13a1f137fd9fedf44a6624e9d500f76d0d46a3c3e9d19c2cda9d28a + languageName: node + linkType: hard + +"@codemirror/search@npm:^6.3.0": + version: 6.3.0 + resolution: "@codemirror/search@npm:6.3.0" + dependencies: + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 + crelt: ^1.0.5 + checksum: b757eebbb541c9d74fe36ccfdd03bc3e4e7aebb08b491e207d5898f24aaa612558c393ba49de5bf375972f5774de817fcfbad1ac551dda1a34badb41cf130d36 + languageName: node + linkType: hard + +"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.4, @codemirror/state@npm:^6.2.0": + version: 6.2.0 + resolution: "@codemirror/state@npm:6.2.0" + checksum: fdc99c773dc09c700dd02bf918f06132aa8d3069c262cc4eb6ca5c810ce24ae2d7e90719ae7630a8158fd263018de6d40bd78f312e6bfba754e737b64e6c6b3d + languageName: node + linkType: hard + +"@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.2.2, @codemirror/view@npm:^6.6.0, @codemirror/view@npm:^6.9.6": + version: 6.9.6 + resolution: "@codemirror/view@npm:6.9.6" + dependencies: + "@codemirror/state": ^6.1.4 + style-mod: ^4.0.0 + w3c-keyname: ^2.2.4 + checksum: af6f3f66b26234e35a7036562d9f43f309b75b048e68b6300b0ccc6f7a13ac2a1aa4e16f84ebd05a8ded039549efc19cf495fea66593726f6ffebe45c0117418 + languageName: node + linkType: hard + +"@csstools/css-parser-algorithms@npm:^2.3.0": + version: 2.3.0 + resolution: "@csstools/css-parser-algorithms@npm:2.3.0" + peerDependencies: + "@csstools/css-tokenizer": ^2.1.1 + checksum: 3be22a0cfcfe0dc4bb140e2f266590addf21c5052d9e69334da860b3839fbd4369c3d158cbc396032d5ed96d01d2b5d8ebdb5497f75c9830ed9ce99853e3f915 + languageName: node + linkType: hard + +"@csstools/css-tokenizer@npm:^2.1.1": + version: 2.1.1 + resolution: "@csstools/css-tokenizer@npm:2.1.1" + checksum: d6ac4b08d7fdfc146755542f00b208af7248efd6cf2eb0f0f7d2ba3583a81f08ed9be6047d78b046925708b5bd0886f487edeeee2f90f0f34030dcbef4122d0e + languageName: node + linkType: hard + +"@csstools/media-query-list-parser@npm:^2.1.2": + version: 2.1.2 + resolution: "@csstools/media-query-list-parser@npm:2.1.2" + peerDependencies: + "@csstools/css-parser-algorithms": ^2.3.0 + "@csstools/css-tokenizer": ^2.1.1 + checksum: 04936573ba837f14d7d637e172342c473665679c6497bbc0d548d93d08cb22e22151bb19e0e20422954c0b2aa50c3f38c9fc5f45c136e31bc863c656cb79df1b + languageName: node + linkType: hard + +"@csstools/selector-specificity@npm:^3.0.0": + version: 3.0.0 + resolution: "@csstools/selector-specificity@npm:3.0.0" + peerDependencies: + postcss-selector-parser: ^6.0.13 + checksum: 4a2dfe69998a499155d9dab4c2a0e7ae7594d8db98bb8a487d2d5347c0c501655051eb5eacad3fe323c86b0ba8212fe092c27fc883621e6ac2a27662edfc3528 + languageName: node + linkType: hard + +"@discoveryjs/json-ext@npm:0.5.7, @discoveryjs/json-ext@npm:^0.5.0": + version: 0.5.7 + resolution: "@discoveryjs/json-ext@npm:0.5.7" + checksum: 2176d301cc258ea5c2324402997cf8134ebb212469c0d397591636cea8d3c02f2b3cf9fd58dcb748c7a0dade77ebdc1b10284fa63e608c033a1db52fddc69918 + languageName: node + linkType: hard + +"@eslint-community/eslint-utils@npm:^4.2.0": + version: 4.3.0 + resolution: "@eslint-community/eslint-utils@npm:4.3.0" + dependencies: + eslint-visitor-keys: ^3.3.0 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: f487760a692f0f1fef76e248ad72976919576ba57edc2b1b1dc1d182553bae6b5bf7b078e654da85d04f0af8a485d20bd26280002768f4fbcd2e330078340cb0 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.4.0": + version: 4.4.0 + resolution: "@eslint-community/regexpp@npm:4.4.0" + checksum: 2d127af0c752b80e8a782eacfe996a86925d21de92da3ffc6f9e615e701145e44a62e26bdd88bfac2cd76779c39ba8d9875a91046ec5e7e5f23cb647c247ea6a + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^2.0.1": + version: 2.0.1 + resolution: "@eslint/eslintrc@npm:2.0.1" + dependencies: + ajv: ^6.12.4 + debug: ^4.3.2 + espree: ^9.5.0 + globals: ^13.19.0 + ignore: ^5.2.0 + import-fresh: ^3.2.1 + js-yaml: ^4.1.0 + minimatch: ^3.1.2 + strip-json-comments: ^3.1.1 + checksum: 56b9192a687a450db53a7b883daf9f0f447c43b3510189cf88808a7a2467c2a302a42a50f184cc6d5a9faf3d1df890a2ef0fd0d60b751f32a3e9dfea717c6b48 + languageName: node + linkType: hard + +"@eslint/js@npm:8.36.0": + version: 8.36.0 + resolution: "@eslint/js@npm:8.36.0" + checksum: b7d6b84b823c8c7784be390741196617565527b1f7c0977fde9455bfb57fd88f81c074a03dd878757d2c33fa29f24291e9ecbc1425710f067917324b55e1bf3a + languageName: node + linkType: hard + +"@fortawesome/fontawesome-free@npm:^5.12.0": + version: 5.15.4 + resolution: "@fortawesome/fontawesome-free@npm:5.15.4" + checksum: 32281c3df4075290d9a96dfc22f72fadb3da7055d4117e48d34046b8c98032a55fa260ae351b0af5d6f6fb57a2f5d79a4abe52af456da35195f7cb7dda27b4a2 + languageName: node + linkType: hard + +"@gar/promisify@npm:^1.1.3": + version: 1.1.3 + resolution: "@gar/promisify@npm:1.1.3" + checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1 + languageName: node + linkType: hard + +"@humanwhocodes/config-array@npm:^0.11.8": + version: 0.11.8 + resolution: "@humanwhocodes/config-array@npm:0.11.8" + dependencies: + "@humanwhocodes/object-schema": ^1.2.1 + debug: ^4.1.1 + minimatch: ^3.0.5 + checksum: 0fd6b3c54f1674ce0a224df09b9c2f9846d20b9e54fabae1281ecfc04f2e6ad69bf19e1d6af6a28f88e8aa3990168b6cb9e1ef755868c3256a630605ec2cb1d3 + languageName: node + linkType: hard + +"@humanwhocodes/module-importer@npm:^1.0.1": + version: 1.0.1 + resolution: "@humanwhocodes/module-importer@npm:1.0.1" + checksum: 0fd22007db8034a2cdf2c764b140d37d9020bbfce8a49d3ec5c05290e77d4b0263b1b972b752df8c89e5eaa94073408f2b7d977aed131faf6cf396ebb5d7fb61 + languageName: node + linkType: hard + +"@humanwhocodes/object-schema@npm:^1.2.1": + version: 1.2.1 + resolution: "@humanwhocodes/object-schema@npm:1.2.1" + checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 + languageName: node + linkType: hard + +"@hutson/parse-repository-url@npm:^3.0.0": + version: 3.0.2 + resolution: "@hutson/parse-repository-url@npm:3.0.2" + checksum: 39992c5f183c5ca3d761d6ed9dfabcb79b5f3750bf1b7f3532e1dc439ca370138bbd426ee250fdaba460bc948e6761fbefd484b8f4f36885d71ded96138340d1 + languageName: node + linkType: hard + +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: ^5.1.2 + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: ^7.0.1 + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: ^8.1.0 + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 4a473b9b32a7d4d3cfb7a614226e555091ff0c5a29a1734c28c72a182c2f6699b26fc6b5c2131dfd841e86b185aea714c72201d7c98c2fba5f17709333a67aeb + languageName: node + linkType: hard + +"@istanbuljs/load-nyc-config@npm:^1.0.0": + version: 1.1.0 + resolution: "@istanbuljs/load-nyc-config@npm:1.1.0" + 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 + checksum: d578da5e2e804d5c93228450a1380e1a3c691de4953acc162f387b717258512a3e07b83510a936d9fab03eac90817473917e24f5d16297af3867f59328d58568 + languageName: node + linkType: hard + +"@istanbuljs/schema@npm:^0.1.2": + version: 0.1.3 + resolution: "@istanbuljs/schema@npm:0.1.3" + checksum: 5282759d961d61350f33d9118d16bcaed914ebf8061a52f4fa474b2cb08720c9c81d165e13b82f2e5a8a212cc5af482f0c6fc1ac27b9e067e5394c9a6ed186c9 + languageName: node + linkType: hard + +"@jest/console@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/console@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + slash: ^3.0.0 + checksum: 9f4f4b8fabd1221361b7f2e92d4a90f5f8c2e2b29077249996ab3c8b7f765175ffee795368f8d6b5b2bb3adb32dc09319f7270c7c787b0d259e624e00e0f64a5 + languageName: node + linkType: hard + +"@jest/core@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/core@npm:29.5.0" + dependencies: + "@jest/console": ^29.5.0 + "@jest/reporters": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + ansi-escapes: ^4.2.1 + chalk: ^4.0.0 + ci-info: ^3.2.0 + exit: ^0.1.2 + graceful-fs: ^4.2.9 + jest-changed-files: ^29.5.0 + jest-config: ^29.5.0 + jest-haste-map: ^29.5.0 + jest-message-util: ^29.5.0 + jest-regex-util: ^29.4.3 + jest-resolve: ^29.5.0 + jest-resolve-dependencies: ^29.5.0 + jest-runner: ^29.5.0 + jest-runtime: ^29.5.0 + jest-snapshot: ^29.5.0 + jest-util: ^29.5.0 + jest-validate: ^29.5.0 + jest-watcher: ^29.5.0 + micromatch: ^4.0.4 + pretty-format: ^29.5.0 + slash: ^3.0.0 + strip-ansi: ^6.0.0 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + checksum: 9e8f5243fe82d5a57f3971e1b96f320058df7c315328a3a827263f3b17f64be10c80f4a9c1b1773628b64d2de6d607c70b5b2d5bf13e7f5ad04223e9ef6aac06 + languageName: node + linkType: hard + +"@jest/environment@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/environment@npm:29.5.0" + dependencies: + "@jest/fake-timers": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + jest-mock: ^29.5.0 + checksum: 921de6325cd4817dec6685e5ff299b499b6379f3f9cf489b4b13588ee1f3820a0c77b49e6a087996b6de8f629f6f5251e636cba08d1bdb97d8071cc7d033c88a + languageName: node + linkType: hard + +"@jest/expect-utils@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/expect-utils@npm:29.5.0" + dependencies: + jest-get-type: ^29.4.3 + checksum: c46fb677c88535cf83cf29f0a5b1f376c6a1109ddda266ad7da1a9cbc53cb441fa402dd61fc7b111ffc99603c11a9b3357ee41a1c0e035a58830bcb360871476 + languageName: node + linkType: hard + +"@jest/expect@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/expect@npm:29.5.0" + dependencies: + expect: ^29.5.0 + jest-snapshot: ^29.5.0 + checksum: bd10e295111547e6339137107d83986ab48d46561525393834d7d2d8b2ae9d5626653f3f5e48e5c3fa742ac982e97bdf1f541b53b9e1d117a247b08e938527f6 + languageName: node + linkType: hard + +"@jest/fake-timers@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/fake-timers@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@sinonjs/fake-timers": ^10.0.2 + "@types/node": "*" + jest-message-util: ^29.5.0 + jest-mock: ^29.5.0 + jest-util: ^29.5.0 + checksum: 69930c6922341f244151ec0d27640852ec96237f730fc024da1f53143d31b43cde75d92f9d8e5937981cdce3b31416abc3a7090a0d22c2377512c4a6613244ee + languageName: node + linkType: hard + +"@jest/globals@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/globals@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/expect": ^29.5.0 + "@jest/types": ^29.5.0 + jest-mock: ^29.5.0 + checksum: b309ab8f21b571a7c672608682e84bbdd3d2b554ddf81e4e32617fec0a69094a290ab42e3c8b2c66ba891882bfb1b8b2736720ea1285b3ad646d55c2abefedd9 + languageName: node + linkType: hard + +"@jest/reporters@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/reporters@npm:29.5.0" + dependencies: + "@bcoe/v8-coverage": ^0.2.3 + "@jest/console": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@jridgewell/trace-mapping": ^0.3.15 + "@types/node": "*" + chalk: ^4.0.0 + collect-v8-coverage: ^1.0.0 + exit: ^0.1.2 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + istanbul-lib-coverage: ^3.0.0 + istanbul-lib-instrument: ^5.1.0 + istanbul-lib-report: ^3.0.0 + istanbul-lib-source-maps: ^4.0.0 + istanbul-reports: ^3.1.3 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + jest-worker: ^29.5.0 + slash: ^3.0.0 + string-length: ^4.0.1 + strip-ansi: ^6.0.0 + v8-to-istanbul: ^9.0.1 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + checksum: 481268aac9a4a75cc49c4df1273d6b111808dec815e9d009dad717c32383ebb0cebac76e820ad1ab44e207540e1c2fe1e640d44c4f262de92ab1933e057fdeeb + languageName: node + linkType: hard + +"@jest/schemas@npm:^29.4.3": + version: 29.4.3 + resolution: "@jest/schemas@npm:29.4.3" + dependencies: + "@sinclair/typebox": ^0.25.16 + checksum: ac754e245c19dc39e10ebd41dce09040214c96a4cd8efa143b82148e383e45128f24599195ab4f01433adae4ccfbe2db6574c90db2862ccd8551a86704b5bebd + languageName: node + linkType: hard + +"@jest/source-map@npm:^29.4.3": + version: 29.4.3 + resolution: "@jest/source-map@npm:29.4.3" + dependencies: + "@jridgewell/trace-mapping": ^0.3.15 + callsites: ^3.0.0 + graceful-fs: ^4.2.9 + checksum: 2301d225145f8123540c0be073f35a80fd26a2f5e59550fd68525d8cea580fb896d12bf65106591ffb7366a8a19790076dbebc70e0f5e6ceb51f81827ed1f89c + languageName: node + linkType: hard + +"@jest/test-result@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/test-result@npm:29.5.0" + dependencies: + "@jest/console": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/istanbul-lib-coverage": ^2.0.0 + collect-v8-coverage: ^1.0.0 + checksum: 2e8ff5242227ab960c520c3ea0f6544c595cc1c42fa3873c158e9f4f685f4ec9670ec08a4af94ae3885c0005a43550a9595191ffbc27a0965df27d9d98bbf901 + languageName: node + linkType: hard + +"@jest/test-sequencer@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/test-sequencer@npm:29.5.0" + dependencies: + "@jest/test-result": ^29.5.0 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.5.0 + slash: ^3.0.0 + checksum: eca34b4aeb2fda6dfb7f9f4b064c858a7adf64ec5c6091b6f4ed9d3c19549177cbadcf1c615c4c182688fa1cf085c8c55c3ca6eea40719a34554b0bf071d842e + languageName: node + linkType: hard + +"@jest/transform@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/transform@npm:29.5.0" + dependencies: + "@babel/core": ^7.11.6 + "@jest/types": ^29.5.0 + "@jridgewell/trace-mapping": ^0.3.15 + babel-plugin-istanbul: ^6.1.1 + chalk: ^4.0.0 + convert-source-map: ^2.0.0 + fast-json-stable-stringify: ^2.1.0 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.5.0 + jest-regex-util: ^29.4.3 + jest-util: ^29.5.0 + micromatch: ^4.0.4 + pirates: ^4.0.4 + slash: ^3.0.0 + write-file-atomic: ^4.0.2 + checksum: d55d604085c157cf5112e165ff5ac1fa788873b3b31265fb4734ca59892ee24e44119964cc47eb6d178dd9512bbb6c576d1e20e51a201ff4e24d31e818a1c92d + languageName: node + linkType: hard + +"@jest/types@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/types@npm:29.5.0" + dependencies: + "@jest/schemas": ^29.4.3 + "@types/istanbul-lib-coverage": ^2.0.0 + "@types/istanbul-reports": ^3.0.0 + "@types/node": "*" + "@types/yargs": ^17.0.8 + chalk: ^4.0.0 + checksum: 1811f94b19cf8a9460a289c4f056796cfc373480e0492692a6125a553cd1a63824bd846d7bb78820b7b6f758f6dd3c2d4558293bb676d541b2fa59c70fdf9d39 + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.1.0": + version: 0.1.1 + resolution: "@jridgewell/gen-mapping@npm:0.1.1" + dependencies: + "@jridgewell/set-array": ^1.0.0 + "@jridgewell/sourcemap-codec": ^1.4.10 + checksum: 3bcc21fe786de6ffbf35c399a174faab05eb23ce6a03e8769569de28abbf4facc2db36a9ddb0150545ae23a8d35a7cf7237b2aa9e9356a7c626fb4698287d5cc + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": + version: 0.3.2 + resolution: "@jridgewell/gen-mapping@npm:0.3.2" + dependencies: + "@jridgewell/set-array": ^1.0.1 + "@jridgewell/sourcemap-codec": ^1.4.10 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 1832707a1c476afebe4d0fbbd4b9434fdb51a4c3e009ab1e9938648e21b7a97049fa6009393bdf05cab7504108413441df26d8a3c12193996e65493a4efb6882 + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:3.1.0": + version: 3.1.0 + resolution: "@jridgewell/resolve-uri@npm:3.1.0" + checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267 + languageName: node + linkType: hard + +"@jridgewell/set-array@npm:^1.0.0, @jridgewell/set-array@npm:^1.0.1": + version: 1.1.2 + resolution: "@jridgewell/set-array@npm:1.1.2" + checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e + languageName: node + linkType: hard + +"@jridgewell/source-map@npm:^0.3.2": + version: 0.3.2 + resolution: "@jridgewell/source-map@npm:0.3.2" + dependencies: + "@jridgewell/gen-mapping": ^0.3.0 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 1b83f0eb944e77b70559a394d5d3b3f98a81fcc186946aceb3ef42d036762b52ef71493c6c0a3b7c1d2f08785f53ba2df1277fe629a06e6109588ff4cdcf7482 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.10": + version: 1.4.14 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" + checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.17 + resolution: "@jridgewell/trace-mapping@npm:0.3.17" + dependencies: + "@jridgewell/resolve-uri": 3.1.0 + "@jridgewell/sourcemap-codec": 1.4.14 + checksum: 9d703b859cff5cd83b7308fd457a431387db5db96bd781a63bf48e183418dd9d3d44e76b9e4ae13237f6abeeb25d739ec9215c1d5bfdd08f66f750a50074a339 + languageName: node + linkType: hard + +"@jupyter/ydoc@npm:^1.0.2": + version: 1.0.2 + resolution: "@jupyter/ydoc@npm:1.0.2" + dependencies: + "@jupyterlab/nbformat": ^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0 + "@lumino/coreutils": ^1.11.0 || ^2.0.0 + "@lumino/disposable": ^1.10.0 || ^2.0.0 + "@lumino/signaling": ^1.10.0 || ^2.0.0 + y-protocols: ^1.0.5 + yjs: ^13.5.40 + checksum: 739f9630940466b3cfcd7b742dd06479f81772ca13f863d057af0bbb5e318829506969066ab72977e7c721644982b5c8f88cf44e1ae81955ed1c27e87632d1f2 + languageName: node + linkType: hard + +"@jupyterlab/application-extension@^4.0.8, @jupyterlab/application-extension@workspace:packages/application-extension, @jupyterlab/application-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/application-extension@workspace:packages/application-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/property-inspector": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/application-top@workspace:dev_mode": + version: 0.0.0-use.local + resolution: "@jupyterlab/application-top@workspace:dev_mode" + dependencies: + "@jupyterlab/application": ~4.0.8 + "@jupyterlab/application-extension": ~4.0.8 + "@jupyterlab/apputils-extension": ~4.0.8 + "@jupyterlab/builder": ^4.0.8 + "@jupyterlab/buildutils": ^4.0.8 + "@jupyterlab/cell-toolbar-extension": ~4.0.8 + "@jupyterlab/celltags-extension": ~4.0.8 + "@jupyterlab/codemirror-extension": ~4.0.8 + "@jupyterlab/completer-extension": ~4.0.8 + "@jupyterlab/console-extension": ~4.0.8 + "@jupyterlab/coreutils": ~6.0.8 + "@jupyterlab/csvviewer-extension": ~4.0.8 + "@jupyterlab/debugger-extension": ~4.0.8 + "@jupyterlab/docmanager-extension": ~4.0.8 + "@jupyterlab/documentsearch-extension": ~4.0.8 + "@jupyterlab/extensionmanager-extension": ~4.0.8 + "@jupyterlab/filebrowser-extension": ~4.0.8 + "@jupyterlab/fileeditor-extension": ~4.0.8 + "@jupyterlab/help-extension": ~4.0.8 + "@jupyterlab/htmlviewer-extension": ~4.0.8 + "@jupyterlab/hub-extension": ~4.0.8 + "@jupyterlab/imageviewer-extension": ~4.0.8 + "@jupyterlab/inspector-extension": ~4.0.8 + "@jupyterlab/javascript-extension": ~4.0.8 + "@jupyterlab/json-extension": ~4.0.8 + "@jupyterlab/launcher-extension": ~4.0.8 + "@jupyterlab/logconsole-extension": ~4.0.8 + "@jupyterlab/lsp-extension": ~4.0.8 + "@jupyterlab/mainmenu-extension": ~4.0.8 + "@jupyterlab/markdownviewer-extension": ~4.0.8 + "@jupyterlab/markedparser-extension": ~4.0.8 + "@jupyterlab/mathjax-extension": ~4.0.8 + "@jupyterlab/metadataform-extension": ~4.0.8 + "@jupyterlab/notebook-extension": ~4.0.8 + "@jupyterlab/pdf-extension": ~4.0.8 + "@jupyterlab/rendermime-extension": ~4.0.8 + "@jupyterlab/running-extension": ~4.0.8 + "@jupyterlab/settingeditor-extension": ~4.0.8 + "@jupyterlab/shortcuts-extension": ~4.0.8 + "@jupyterlab/statusbar-extension": ~4.0.8 + "@jupyterlab/terminal-extension": ~4.0.8 + "@jupyterlab/theme-dark-extension": ~4.0.8 + "@jupyterlab/theme-light-extension": ~4.0.8 + "@jupyterlab/toc-extension": ~6.0.8 + "@jupyterlab/tooltip-extension": ~4.0.8 + "@jupyterlab/translation-extension": ~4.0.8 + "@jupyterlab/ui-components-extension": ~4.0.8 + "@jupyterlab/vega5-extension": ~4.0.8 + chokidar: ^3.4.0 + css-loader: ^6.7.1 + duplicate-package-checker-webpack-plugin: ^3.0.0 + fs-extra: ^10.1.0 + glob: ~7.1.6 + handlebars: ^4.5.3 + html-loader: ~1.3.0 + html-webpack-plugin: ^5.5.0 + license-webpack-plugin: ^4.0.2 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + rimraf: ~3.0.0 + sort-package-json: ~1.53.1 + source-map-loader: ~1.0.2 + style-loader: ~3.3.1 + terser-webpack-plugin: ^5.3.7 + webpack: ^5.76.1 + webpack-bundle-analyzer: ^4.8.0 + webpack-cli: ^5.0.1 + webpack-merge: ^5.8.0 + whatwg-fetch: ^3.0.0 + worker-loader: ^3.0.2 + languageName: unknown + linkType: soft + +"@jupyterlab/application@^4.0.8, @jupyterlab/application@workspace:packages/application, @jupyterlab/application@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/application@workspace:packages/application" + dependencies: + "@fortawesome/fontawesome-free": ^5.12.0 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/application": ^2.2.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/apputils-extension@^4.0.8, @jupyterlab/apputils-extension@workspace:packages/apputils-extension, @jupyterlab/apputils-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/apputils-extension@workspace:packages/apputils-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + react-dom: ^18.2.0 + react-toastify: ^9.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/apputils@^4.1.8, @jupyterlab/apputils@workspace:packages/apputils": + version: 0.0.0-use.local + resolution: "@jupyterlab/apputils@workspace:packages/apputils" + dependencies: + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + "@types/react": ^18.0.26 + "@types/sanitize-html": ^2.3.1 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + sanitize-html: ~2.7.3 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/attachments@^4.0.8, @jupyterlab/attachments@workspace:packages/attachments": + version: 0.0.0-use.local + resolution: "@jupyterlab/attachments@workspace:packages/attachments" + dependencies: + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/builder@^4.0.8, @jupyterlab/builder@workspace:builder": + version: 0.0.0-use.local + resolution: "@jupyterlab/builder@workspace:builder" + dependencies: + "@lumino/algorithm": ^2.0.1 + "@lumino/application": ^2.2.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/dragdrop": ^2.1.3 + "@lumino/messaging": ^2.0.1 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/fs-extra": ^9.0.1 + "@types/glob": ^7.1.1 + "@types/node": ^18.11.18 + "@types/supports-color": ^5.3.0 + ajv: ^8.12.0 + commander: ^9.4.1 + css-loader: ^6.7.1 + duplicate-package-checker-webpack-plugin: ^3.0.0 + fs-extra: ^10.1.0 + glob: ~7.1.6 + license-webpack-plugin: ^2.3.14 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + path-browserify: ^1.0.0 + process: ^0.11.10 + rimraf: ~3.0.0 + source-map-loader: ~1.0.2 + style-loader: ~3.3.1 + supports-color: ^7.2.0 + terser-webpack-plugin: ^5.3.7 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + webpack-merge: ^5.8.0 + worker-loader: ^3.0.2 + bin: + build-labextension: ./lib/build-labextension.js + languageName: unknown + linkType: soft + +"@jupyterlab/buildutils@^4.0.8, @jupyterlab/buildutils@workspace:buildutils": + version: 0.0.0-use.local + resolution: "@jupyterlab/buildutils@workspace:buildutils" + dependencies: + "@types/fs-extra": ^9.0.1 + "@types/glob": ^7.1.1 + "@types/inquirer": ^9.0.3 + "@types/micromatch": ^4.0.1 + "@types/node": ^18.11.18 + "@types/prettier": ~2.6.0 + "@yarnpkg/core": ^3.0.0 + "@yarnpkg/parsers": ^2.0.0 + child_process: ~1.0.2 + commander: ^9.4.1 + crypto: ~1.0.1 + dependency-graph: ^0.11.0 + fs-extra: ^10.1.0 + glob: ~7.1.6 + inquirer: ^9.1.4 + micromatch: ^4.0.2 + minimatch: ~3.0.4 + os: ~0.1.1 + package-json: ^7.0.0 + prettier: ~2.6.0 + process: ^0.11.10 + rimraf: ~3.0.0 + semver: ^7.3.2 + sort-package-json: ~1.53.1 + typescript: ~5.0.4 + verdaccio: ^5.25.0 + bin: + get-dependency: ./lib/get-dependency.js + local-repository: ./lib/local-repository.js + remove-dependency: ./lib/remove-dependency.js + update-dependency: ./lib/update-dependency.js + update-dist-tag: ./lib/update-dist-tag.js + update-staging-lock: ./lib/update-staging-lock.js + languageName: unknown + linkType: soft + +"@jupyterlab/cell-toolbar-extension@^4.0.8, @jupyterlab/cell-toolbar-extension@workspace:packages/cell-toolbar-extension, @jupyterlab/cell-toolbar-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/cell-toolbar-extension@workspace:packages/cell-toolbar-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cell-toolbar": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/cell-toolbar@^4.0.8, @jupyterlab/cell-toolbar@workspace:packages/cell-toolbar": + version: 0.0.0-use.local + resolution: "@jupyterlab/cell-toolbar@workspace:packages/cell-toolbar" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/cells@^4.0.8, @jupyterlab/cells@workspace:packages/cells": + version: 0.0.0-use.local + resolution: "@jupyterlab/cells@workspace:packages/cells" + dependencies: + "@codemirror/state": ^6.2.0 + "@codemirror/view": ^6.9.6 + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/attachments": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/outputarea": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/dragdrop": ^2.1.3 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + "@types/react": ^18.0.26 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/celltags-extension@^4.0.8, @jupyterlab/celltags-extension@workspace:packages/celltags-extension, @jupyterlab/celltags-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/celltags-extension@workspace:packages/celltags-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@rjsf/utils": ^5.1.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/codeeditor@^4.0.8, @jupyterlab/codeeditor@workspace:packages/codeeditor": + version: 0.0.0-use.local + resolution: "@jupyterlab/codeeditor@workspace:packages/codeeditor" + dependencies: + "@codemirror/state": ^6.2.0 + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/dragdrop": ^2.1.3 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/codemirror-extension@^4.0.8, @jupyterlab/codemirror-extension@workspace:packages/codemirror-extension, @jupyterlab/codemirror-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/codemirror-extension@workspace:packages/codemirror-extension" + dependencies: + "@codemirror/lang-markdown": ^6.1.1 + "@codemirror/language": ^6.6.0 + "@codemirror/legacy-modes": ^6.3.2 + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@rjsf/utils": ^5.1.0 + "@rjsf/validator-ajv8": ^5.1.0 + "@types/react": ^18.0.26 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/codemirror@^4.0.8, @jupyterlab/codemirror@workspace:packages/codemirror": + version: 0.0.0-use.local + resolution: "@jupyterlab/codemirror@workspace:packages/codemirror" + dependencies: + "@codemirror/autocomplete": ^6.5.1 + "@codemirror/commands": ^6.2.3 + "@codemirror/lang-cpp": ^6.0.2 + "@codemirror/lang-css": ^6.1.1 + "@codemirror/lang-html": ^6.4.3 + "@codemirror/lang-java": ^6.0.1 + "@codemirror/lang-javascript": ^6.1.7 + "@codemirror/lang-json": ^6.0.1 + "@codemirror/lang-markdown": ^6.1.1 + "@codemirror/lang-php": ^6.0.1 + "@codemirror/lang-python": ^6.1.3 + "@codemirror/lang-rust": ^6.0.1 + "@codemirror/lang-sql": ^6.4.1 + "@codemirror/lang-wast": ^6.0.1 + "@codemirror/lang-xml": ^6.0.2 + "@codemirror/language": ^6.6.0 + "@codemirror/legacy-modes": ^6.3.2 + "@codemirror/search": ^6.3.0 + "@codemirror/state": ^6.2.0 + "@codemirror/view": ^6.9.6 + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lezer/common": ^1.0.2 + "@lezer/generator": ^1.2.2 + "@lezer/highlight": ^1.1.4 + "@lezer/lr": ^1.3.3 + "@lezer/markdown": ^1.0.2 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + yjs: ^13.5.40 + languageName: unknown + linkType: soft + +"@jupyterlab/completer-extension@^4.0.8, @jupyterlab/completer-extension@workspace:packages/completer-extension, @jupyterlab/completer-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/completer-extension@workspace:packages/completer-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/completer": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@rjsf/utils": ^5.1.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/completer@^4.0.8, @jupyterlab/completer@workspace:packages/completer": + version: 0.0.0-use.local + resolution: "@jupyterlab/completer@workspace:packages/completer" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/console-extension@^4.0.8, @jupyterlab/console-extension@workspace:packages/console-extension, @jupyterlab/console-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/console-extension@workspace:packages/console-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/completer": ^4.0.8 + "@jupyterlab/console": ^4.0.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/launcher": ^4.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/console@^4.0.8, @jupyterlab/console@workspace:packages/console": + version: 0.0.0-use.local + resolution: "@jupyterlab/console@workspace:packages/console" + dependencies: + "@codemirror/state": ^6.2.0 + "@codemirror/view": ^6.9.6 + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/dragdrop": ^2.1.3 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/coreutils@^6.0.8, @jupyterlab/coreutils@workspace:packages/coreutils, @jupyterlab/coreutils@~6.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/coreutils@workspace:packages/coreutils" + dependencies: + "@babel/core": ^7.10.2 + "@babel/preset-env": ^7.10.2 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@types/jest": ^29.2.0 + "@types/minimist": ^1.2.0 + "@types/url-parse": ^1.4.3 + jest: ^29.2.0 + jest-environment-jsdom: ^29.3.0 + jest-junit: ^15.0.0 + minimist: ~1.2.0 + path-browserify: ^1.0.0 + rimraf: ~3.0.0 + ts-jest: ^29.1.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + url-parse: ~1.5.4 + languageName: unknown + linkType: soft + +"@jupyterlab/csvviewer-extension@^4.0.8, @jupyterlab/csvviewer-extension@workspace:packages/csvviewer-extension, @jupyterlab/csvviewer-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/csvviewer-extension@workspace:packages/csvviewer-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/csvviewer": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/datagrid": ^2.2.0 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/csvviewer@^4.0.8, @jupyterlab/csvviewer@workspace:packages/csvviewer": + version: 0.0.0-use.local + resolution: "@jupyterlab/csvviewer@workspace:packages/csvviewer" + dependencies: + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/datagrid": ^2.2.0 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + canvas: ^2.11.2 + csv-spectrum: ^1.0.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/debugger-extension@^4.0.8, @jupyterlab/debugger-extension@workspace:packages/debugger-extension, @jupyterlab/debugger-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/debugger-extension@workspace:packages/debugger-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/console": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/debugger": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/fileeditor": ^4.0.8 + "@jupyterlab/logconsole": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@types/jest": ^29.2.0 + "@types/react-dom": ^18.0.9 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/debugger@^4.0.8, @jupyterlab/debugger@workspace:packages/debugger": + version: 0.0.0-use.local + resolution: "@jupyterlab/debugger@workspace:packages/debugger" + dependencies: + "@codemirror/state": ^6.2.0 + "@codemirror/view": ^6.9.6 + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/console": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/fileeditor": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/datagrid": ^2.2.0 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + "@vscode/debugprotocol": ^1.51.0 + canvas: ^2.11.2 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/docmanager-extension@^4.0.8, @jupyterlab/docmanager-extension@workspace:packages/docmanager-extension, @jupyterlab/docmanager-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/docmanager-extension@workspace:packages/docmanager-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/docmanager@^4.0.8, @jupyterlab/docmanager@workspace:packages/docmanager": + version: 0.0.0-use.local + resolution: "@jupyterlab/docmanager@workspace:packages/docmanager" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/docregistry@^4.0.8, @jupyterlab/docregistry@workspace:packages/docregistry": + version: 0.0.0-use.local + resolution: "@jupyterlab/docregistry@workspace:packages/docregistry" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/documentsearch-extension@^4.0.8, @jupyterlab/documentsearch-extension@workspace:packages/documentsearch-extension, @jupyterlab/documentsearch-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/documentsearch-extension@workspace:packages/documentsearch-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/documentsearch@^4.0.8, @jupyterlab/documentsearch@workspace:packages/documentsearch": + version: 0.0.0-use.local + resolution: "@jupyterlab/documentsearch@workspace:packages/documentsearch" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/example-app@workspace:examples/app": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-app@workspace:examples/app" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/application-extension": ^4.0.8 + "@jupyterlab/apputils-extension": ^4.0.8 + "@jupyterlab/builder": ^4.0.8 + "@jupyterlab/celltags-extension": ^4.0.8 + "@jupyterlab/codemirror-extension": ^4.0.8 + "@jupyterlab/completer-extension": ^4.0.8 + "@jupyterlab/console-extension": ^4.0.8 + "@jupyterlab/csvviewer-extension": ^4.0.8 + "@jupyterlab/docmanager-extension": ^4.0.8 + "@jupyterlab/filebrowser-extension": ^4.0.8 + "@jupyterlab/fileeditor-extension": ^4.0.8 + "@jupyterlab/help-extension": ^4.0.8 + "@jupyterlab/imageviewer-extension": ^4.0.8 + "@jupyterlab/inspector-extension": ^4.0.8 + "@jupyterlab/launcher-extension": ^4.0.8 + "@jupyterlab/mainmenu-extension": ^4.0.8 + "@jupyterlab/markdownviewer-extension": ^4.0.8 + "@jupyterlab/mathjax-extension": ^4.0.8 + "@jupyterlab/metadataform-extension": ^4.0.8 + "@jupyterlab/notebook-extension": ^4.0.8 + "@jupyterlab/rendermime-extension": ^4.0.8 + "@jupyterlab/running-extension": ^4.0.8 + "@jupyterlab/settingeditor-extension": ^4.0.8 + "@jupyterlab/shortcuts-extension": ^4.0.8 + "@jupyterlab/statusbar-extension": ^4.0.8 + "@jupyterlab/theme-dark-extension": ^4.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@jupyterlab/toc-extension": ^6.0.8 + "@jupyterlab/tooltip-extension": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/translation-extension": ^4.0.8 + "@jupyterlab/ui-components-extension": ^4.0.8 + css-loader: ^6.7.1 + fs-extra: ^10.1.0 + glob: ~7.1.6 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + react: ^18.2.0 + react-dom: ^18.2.0 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + whatwg-fetch: ^3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/example-cell@workspace:examples/cell": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-cell@workspace:examples/cell" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/completer": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/commands": ^2.1.3 + "@lumino/widgets": ^2.3.0 + css-loader: ^6.7.1 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + whatwg-fetch: ^3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/example-console@workspace:examples/console": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-console@workspace:examples/console" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/console": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/commands": ^2.1.3 + "@lumino/widgets": ^2.3.0 + css-loader: ^6.7.1 + mini-css-extract-plugin: ^2.7.0 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + whatwg-fetch: ^3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/example-federated-core@workspace:examples/federated/core_package": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-federated-core@workspace:examples/federated/core_package" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/application-extension": ^4.0.8 + "@jupyterlab/apputils-extension": ^4.0.8 + "@jupyterlab/builder": ^4.0.8 + "@jupyterlab/celltags-extension": ^4.0.8 + "@jupyterlab/codemirror-extension": ^4.0.8 + "@jupyterlab/completer-extension": ^4.0.8 + "@jupyterlab/console-extension": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/csvviewer-extension": ^4.0.8 + "@jupyterlab/debugger-extension": ^4.0.8 + "@jupyterlab/docmanager-extension": ^4.0.8 + "@jupyterlab/documentsearch-extension": ^4.0.8 + "@jupyterlab/extensionmanager-extension": ^4.0.8 + "@jupyterlab/filebrowser-extension": ^4.0.8 + "@jupyterlab/fileeditor-extension": ^4.0.8 + "@jupyterlab/help-extension": ^4.0.8 + "@jupyterlab/htmlviewer-extension": ^4.0.8 + "@jupyterlab/hub-extension": ^4.0.8 + "@jupyterlab/imageviewer-extension": ^4.0.8 + "@jupyterlab/inspector-extension": ^4.0.8 + "@jupyterlab/javascript-extension": ^4.0.8 + "@jupyterlab/json-extension": ^4.0.8 + "@jupyterlab/launcher-extension": ^4.0.8 + "@jupyterlab/logconsole-extension": ^4.0.8 + "@jupyterlab/lsp-extension": ^4.0.8 + "@jupyterlab/mainmenu-extension": ^4.0.8 + "@jupyterlab/mathjax-extension": ^4.0.8 + "@jupyterlab/metadataform-extension": ^4.0.8 + "@jupyterlab/notebook-extension": ^4.0.8 + "@jupyterlab/pdf-extension": ^4.0.8 + "@jupyterlab/rendermime-extension": ^4.0.8 + "@jupyterlab/settingeditor-extension": ^4.0.8 + "@jupyterlab/shortcuts-extension": ^4.0.8 + "@jupyterlab/statusbar-extension": ^4.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@jupyterlab/toc-extension": ^6.0.8 + "@jupyterlab/tooltip-extension": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/translation-extension": ^4.0.8 + "@jupyterlab/ui-components-extension": ^4.0.8 + "@jupyterlab/vega5-extension": ^4.0.8 + copy-webpack-plugin: ^11.0.0 + css-loader: ^6.7.1 + fs-extra: ^10.1.0 + glob: ~7.1.6 + handlebars: ^4.5.3 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + webpack-merge: ^5.8.0 + whatwg-fetch: ^3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/example-federated-md@workspace:examples/federated/md_package": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-federated-md@workspace:examples/federated/md_package" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/builder": ^4.0.8 + "@jupyterlab/example-federated-middle": ^3.0.8 + "@jupyterlab/markdownviewer-extension": ^4.0.8 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/example-federated-middle@^3.0.8, @jupyterlab/example-federated-middle@workspace:examples/federated/middle_package": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-federated-middle@workspace:examples/federated/middle_package" + dependencies: + "@jupyterlab/builder": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + rimraf: ~3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/example-federated@workspace:examples/federated": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-federated@workspace:examples/federated" + languageName: unknown + linkType: soft + +"@jupyterlab/example-filebrowser@workspace:examples/filebrowser": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-filebrowser@workspace:examples/filebrowser" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/fileeditor": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/commands": ^2.1.3 + "@lumino/widgets": ^2.3.0 + css-loader: ^6.7.1 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + whatwg-fetch: ^3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/example-notebook@workspace:examples/notebook": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-notebook@workspace:examples/notebook" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/completer": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/markedparser-extension": ^4.0.8 + "@jupyterlab/mathjax-extension": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/commands": ^2.1.3 + "@lumino/widgets": ^2.3.0 + css-loader: ^6.7.1 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + whatwg-fetch: ^3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/example-services-browser@workspace:packages/services/examples/browser": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-services-browser@workspace:packages/services/examples/browser" + dependencies: + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/services": ^7.0.8 + "@lumino/coreutils": ^2.1.2 + rimraf: ~3.0.0 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + languageName: unknown + linkType: soft + +"@jupyterlab/example-services-outputarea@workspace:packages/services/examples/typescript-browser-with-output": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-services-outputarea@workspace:packages/services/examples/typescript-browser-with-output" + dependencies: + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/outputarea": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + css-loader: ^6.7.1 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + languageName: unknown + linkType: soft + +"@jupyterlab/example-simple-list@workspace:packages/ui-components/examples/simple-windowed-list": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-simple-list@workspace:packages/ui-components/examples/simple-windowed-list" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/messaging": ^2.0.1 + "@lumino/widgets": ^2.3.0 + css-loader: ^6.7.1 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + languageName: unknown + linkType: soft + +"@jupyterlab/example-terminal@workspace:examples/terminal": + version: 0.0.0-use.local + resolution: "@jupyterlab/example-terminal@workspace:examples/terminal" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/terminal": ^4.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@lumino/widgets": ^2.3.0 + css-loader: ^6.7.1 + mini-css-extract-plugin: ^2.7.0 + mini-svg-data-uri: ^1.4.4 + rimraf: ~3.0.0 + style-loader: ~3.3.1 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + whatwg-fetch: ^3.0.0 + languageName: unknown + linkType: soft + +"@jupyterlab/extensionmanager-extension@^4.0.8, @jupyterlab/extensionmanager-extension@workspace:packages/extensionmanager-extension, @jupyterlab/extensionmanager-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/extensionmanager-extension@workspace:packages/extensionmanager-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/extensionmanager": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/extensionmanager@^4.0.8, @jupyterlab/extensionmanager@workspace:packages/extensionmanager": + version: 0.0.0-use.local + resolution: "@jupyterlab/extensionmanager@workspace:packages/extensionmanager" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/react": ^18.0.26 + "@types/react-paginate": ^6.2.1 + "@types/semver": ^7.3.3 + jest: ^29.2.0 + react: ^18.2.0 + react-paginate: ^6.3.2 + rimraf: ~3.0.0 + semver: ^7.3.2 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/filebrowser-extension@^4.0.8, @jupyterlab/filebrowser-extension@workspace:packages/filebrowser-extension, @jupyterlab/filebrowser-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/filebrowser-extension@workspace:packages/filebrowser-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/filebrowser@^4.0.8, @jupyterlab/filebrowser@workspace:packages/filebrowser": + version: 0.0.0-use.local + resolution: "@jupyterlab/filebrowser@workspace:packages/filebrowser" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/dragdrop": ^2.1.3 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/fileeditor-extension@^4.0.8, @jupyterlab/fileeditor-extension@workspace:packages/fileeditor-extension, @jupyterlab/fileeditor-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/fileeditor-extension@workspace:packages/fileeditor-extension" + dependencies: + "@codemirror/commands": ^6.2.3 + "@codemirror/search": ^6.3.0 + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/completer": ^4.0.8 + "@jupyterlab/console": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/fileeditor": ^4.0.8 + "@jupyterlab/launcher": ^4.0.8 + "@jupyterlab/lsp": ^4.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/fileeditor@^4.0.8, @jupyterlab/fileeditor@workspace:packages/fileeditor": + version: 0.0.0-use.local + resolution: "@jupyterlab/fileeditor@workspace:packages/fileeditor" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/lsp": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + react: ^18.2.0 + regexp-match-indices: ^1.0.2 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/galata-extension@workspace:galata/extension": + version: 0.0.0-use.local + resolution: "@jupyterlab/galata-extension@workspace:galata/extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/builder": ^4.0.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/debugger": ^4.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/signaling": ^2.1.2 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/galata@workspace:galata": + version: 0.0.0-use.local + resolution: "@jupyterlab/galata@workspace:galata" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/debugger": ^4.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@playwright/test": ^1.32.2 + "@stdlib/stats": ~0.0.13 + fs-extra: ^10.1.0 + json5: ^2.2.3 + path: ~0.12.7 + rimraf: ~3.0.0 + systeminformation: ^5.8.6 + typescript: ~5.0.4 + vega: ^5.20.0 + vega-lite: ^5.6.1 + vega-statistics: ^1.7.9 + languageName: unknown + linkType: soft + +"@jupyterlab/help-extension@^4.0.8, @jupyterlab/help-extension@workspace:packages/help-extension, @jupyterlab/help-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/help-extension@workspace:packages/help-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/htmlviewer-extension@^4.0.8, @jupyterlab/htmlviewer-extension@workspace:packages/htmlviewer-extension, @jupyterlab/htmlviewer-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/htmlviewer-extension@workspace:packages/htmlviewer-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/htmlviewer": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/htmlviewer@^4.0.8, @jupyterlab/htmlviewer@workspace:packages/htmlviewer": + version: 0.0.0-use.local + resolution: "@jupyterlab/htmlviewer@workspace:packages/htmlviewer" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/hub-extension@^4.0.8, @jupyterlab/hub-extension@workspace:packages/hub-extension, @jupyterlab/hub-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/hub-extension@workspace:packages/hub-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/translation": ^4.0.8 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/imageviewer-extension@^4.0.8, @jupyterlab/imageviewer-extension@workspace:packages/imageviewer-extension, @jupyterlab/imageviewer-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/imageviewer-extension@workspace:packages/imageviewer-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/imageviewer": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/imageviewer@^4.0.8, @jupyterlab/imageviewer@workspace:packages/imageviewer": + version: 0.0.0-use.local + resolution: "@jupyterlab/imageviewer@workspace:packages/imageviewer" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/inspector-extension@^4.0.8, @jupyterlab/inspector-extension@workspace:packages/inspector-extension, @jupyterlab/inspector-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/inspector-extension@workspace:packages/inspector-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/console": ^4.0.8 + "@jupyterlab/inspector": ^4.0.8 + "@jupyterlab/launcher": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/inspector@^4.0.8, @jupyterlab/inspector@workspace:packages/inspector": + version: 0.0.0-use.local + resolution: "@jupyterlab/inspector@workspace:packages/inspector" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/javascript-extension@^4.0.8, @jupyterlab/javascript-extension@workspace:packages/javascript-extension, @jupyterlab/javascript-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/javascript-extension@workspace:packages/javascript-extension" + dependencies: + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/json-extension@^4.0.8, @jupyterlab/json-extension@workspace:packages/json-extension, @jupyterlab/json-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/json-extension@workspace:packages/json-extension" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lezer/highlight": ^1.1.4 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/react": ^18.0.26 + "@types/react-dom": ^18.0.9 + "@types/react-highlight-words": ^0.16.4 + react: ^18.2.0 + react-dom: ^18.2.0 + react-highlight-words: ^0.20.0 + react-json-tree: ^0.18.0 + rimraf: ~3.0.0 + style-mod: ^4.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/launcher-extension@^4.0.8, @jupyterlab/launcher-extension@workspace:packages/launcher-extension, @jupyterlab/launcher-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/launcher-extension@workspace:packages/launcher-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/launcher": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/launcher@^4.0.8, @jupyterlab/launcher@workspace:packages/launcher": + version: 0.0.0-use.local + resolution: "@jupyterlab/launcher@workspace:packages/launcher" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/react": ^18.0.26 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/logconsole-extension@^4.0.8, @jupyterlab/logconsole-extension@workspace:packages/logconsole-extension, @jupyterlab/logconsole-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/logconsole-extension@workspace:packages/logconsole-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/logconsole": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/logconsole@^4.0.8, @jupyterlab/logconsole@workspace:packages/logconsole": + version: 0.0.0-use.local + resolution: "@jupyterlab/logconsole@workspace:packages/logconsole" + dependencies: + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/outputarea": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/lsp-extension@^4.0.8, @jupyterlab/lsp-extension@workspace:packages/lsp-extension, @jupyterlab/lsp-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/lsp-extension@workspace:packages/lsp-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/lsp": ^4.0.8 + "@jupyterlab/running": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@rjsf/utils": ^5.1.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/lsp@^4.0.8, @jupyterlab/lsp@workspace:packages/lsp": + version: 0.0.0-use.local + resolution: "@jupyterlab/lsp@workspace:packages/lsp" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@types/jest": ^29.2.0 + "@types/lodash.mergewith": ^4.6.1 + jest: ^29.2.0 + json-schema-to-typescript: ^8.0.0 + lodash.mergewith: ^4.6.1 + rimraf: ~3.0.0 + typescript: ~5.0.4 + vscode-jsonrpc: ^6.0.0 + vscode-languageserver-protocol: ^3.17.0 + vscode-ws-jsonrpc: ~1.0.2 + languageName: unknown + linkType: soft + +"@jupyterlab/mainmenu-extension@^4.0.8, @jupyterlab/mainmenu-extension@workspace:packages/mainmenu-extension, @jupyterlab/mainmenu-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/mainmenu-extension@workspace:packages/mainmenu-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/mainmenu@^4.0.8, @jupyterlab/mainmenu@workspace:packages/mainmenu": + version: 0.0.0-use.local + resolution: "@jupyterlab/mainmenu@workspace:packages/mainmenu" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/markdownviewer-extension@^4.0.8, @jupyterlab/markdownviewer-extension@workspace:packages/markdownviewer-extension, @jupyterlab/markdownviewer-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/markdownviewer-extension@workspace:packages/markdownviewer-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/markdownviewer": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/translation": ^4.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/markdownviewer@^4.0.8, @jupyterlab/markdownviewer@workspace:packages/markdownviewer": + version: 0.0.0-use.local + resolution: "@jupyterlab/markdownviewer@workspace:packages/markdownviewer" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/markedparser-extension@^4.0.8, @jupyterlab/markedparser-extension@workspace:packages/markedparser-extension, @jupyterlab/markedparser-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/markedparser-extension@workspace:packages/markedparser-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@types/marked": ^4.0.3 + marked: ^4.0.17 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/mathjax-extension@^4.0.8, @jupyterlab/mathjax-extension@workspace:packages/mathjax-extension, @jupyterlab/mathjax-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/mathjax-extension@workspace:packages/mathjax-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + mathjax-full: ^3.2.2 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/metadataform-extension@^4.0.8, @jupyterlab/metadataform-extension@workspace:packages/metadataform-extension, @jupyterlab/metadataform-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/metadataform-extension@workspace:packages/metadataform-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/metadataform": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/metadataform@^4.0.8, @jupyterlab/metadataform@workspace:packages/metadataform": + version: 0.0.0-use.local + resolution: "@jupyterlab/metadataform@workspace:packages/metadataform" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@rjsf/core": ^5.1.0 + "@rjsf/validator-ajv8": ^5.1.0 + "@types/jest": ^29.2.0 + "@types/react": ^18.0.26 + jest: ^29.2.0 + json-schema: ^0.4.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/metapackage@workspace:packages/metapackage": + version: 0.0.0-use.local + resolution: "@jupyterlab/metapackage@workspace:packages/metapackage" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/application-extension": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/apputils-extension": ^4.0.8 + "@jupyterlab/attachments": ^4.0.8 + "@jupyterlab/cell-toolbar": ^4.0.8 + "@jupyterlab/cell-toolbar-extension": ^4.0.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/celltags-extension": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/codemirror-extension": ^4.0.8 + "@jupyterlab/completer": ^4.0.8 + "@jupyterlab/completer-extension": ^4.0.8 + "@jupyterlab/console": ^4.0.8 + "@jupyterlab/console-extension": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/csvviewer": ^4.0.8 + "@jupyterlab/csvviewer-extension": ^4.0.8 + "@jupyterlab/debugger": ^4.0.8 + "@jupyterlab/debugger-extension": ^4.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/docmanager-extension": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/documentsearch-extension": ^4.0.8 + "@jupyterlab/extensionmanager": ^4.0.8 + "@jupyterlab/extensionmanager-extension": ^4.0.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/filebrowser-extension": ^4.0.8 + "@jupyterlab/fileeditor": ^4.0.8 + "@jupyterlab/fileeditor-extension": ^4.0.8 + "@jupyterlab/help-extension": ^4.0.8 + "@jupyterlab/htmlviewer": ^4.0.8 + "@jupyterlab/htmlviewer-extension": ^4.0.8 + "@jupyterlab/hub-extension": ^4.0.8 + "@jupyterlab/imageviewer": ^4.0.8 + "@jupyterlab/imageviewer-extension": ^4.0.8 + "@jupyterlab/inspector": ^4.0.8 + "@jupyterlab/inspector-extension": ^4.0.8 + "@jupyterlab/javascript-extension": ^4.0.8 + "@jupyterlab/json-extension": ^4.0.8 + "@jupyterlab/launcher": ^4.0.8 + "@jupyterlab/launcher-extension": ^4.0.8 + "@jupyterlab/logconsole": ^4.0.8 + "@jupyterlab/logconsole-extension": ^4.0.8 + "@jupyterlab/lsp": ^4.0.8 + "@jupyterlab/lsp-extension": ^4.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/mainmenu-extension": ^4.0.8 + "@jupyterlab/markdownviewer": ^4.0.8 + "@jupyterlab/markdownviewer-extension": ^4.0.8 + "@jupyterlab/markedparser-extension": ^4.0.8 + "@jupyterlab/mathjax-extension": ^4.0.8 + "@jupyterlab/metadataform": ^4.0.8 + "@jupyterlab/metadataform-extension": ^4.0.8 + "@jupyterlab/nbconvert-css": ^4.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/notebook-extension": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/outputarea": ^4.0.8 + "@jupyterlab/pdf-extension": ^4.0.8 + "@jupyterlab/property-inspector": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/rendermime-extension": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/running": ^4.0.8 + "@jupyterlab/running-extension": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingeditor": ^4.0.8 + "@jupyterlab/settingeditor-extension": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/shortcuts-extension": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/statusbar-extension": ^4.0.8 + "@jupyterlab/terminal": ^4.0.8 + "@jupyterlab/terminal-extension": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/theme-dark-extension": ^4.0.8 + "@jupyterlab/theme-light-extension": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/toc-extension": ^6.0.8 + "@jupyterlab/tooltip": ^4.0.8 + "@jupyterlab/tooltip-extension": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/translation-extension": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@jupyterlab/ui-components-extension": ^4.0.8 + "@jupyterlab/vega5-extension": ^4.0.8 + "@types/jest": ^29.2.0 + fs-extra: ^10.1.0 + jest: ^29.2.0 + json-to-html: ~0.1.2 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/mock-consumer@workspace:jupyterlab/tests/mock_packages/interop/consumer": + version: 0.0.0-use.local + resolution: "@jupyterlab/mock-consumer@workspace:jupyterlab/tests/mock_packages/interop/consumer" + dependencies: + "@jupyterlab/builder": ^4.0.8 + "@jupyterlab/mock-token": ^4.0.8 + languageName: unknown + linkType: soft + +"@jupyterlab/mock-extension@workspace:jupyterlab/tests/mock_packages/extension": + version: 0.0.0-use.local + resolution: "@jupyterlab/mock-extension@workspace:jupyterlab/tests/mock_packages/extension" + dependencies: + "@jupyterlab/builder": ^4.0.8 + "@jupyterlab/launcher": ^4.0.8 + languageName: unknown + linkType: soft + +"@jupyterlab/mock-provider@workspace:jupyterlab/tests/mock_packages/interop/provider": + version: 0.0.0-use.local + resolution: "@jupyterlab/mock-provider@workspace:jupyterlab/tests/mock_packages/interop/provider" + dependencies: + "@jupyterlab/builder": ^4.0.8 + "@jupyterlab/mock-token": ^4.0.8 + languageName: unknown + linkType: soft + +"@jupyterlab/mock-token@^4.0.8, @jupyterlab/mock-token@workspace:jupyterlab/tests/mock_packages/interop/token": + version: 0.0.0-use.local + resolution: "@jupyterlab/mock-token@workspace:jupyterlab/tests/mock_packages/interop/token" + dependencies: + "@lumino/coreutils": ^2.1.2 + languageName: unknown + linkType: soft + +"@jupyterlab/nbconvert-css@^4.0.8, @jupyterlab/nbconvert-css@workspace:packages/nbconvert-css": + version: 0.0.0-use.local + resolution: "@jupyterlab/nbconvert-css@workspace:packages/nbconvert-css" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/outputarea": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + css-loader: ^6.7.1 + mini-css-extract-plugin: ^2.7.0 + null-loader: ^4.0.0 + rimraf: ~3.0.0 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + languageName: unknown + linkType: soft + +"@jupyterlab/nbformat@^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0, @jupyterlab/nbformat@^4.0.8, @jupyterlab/nbformat@workspace:packages/nbformat": + version: 0.0.0-use.local + resolution: "@jupyterlab/nbformat@workspace:packages/nbformat" + dependencies: + "@jupyterlab/testing": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/notebook-extension@^4.0.8, @jupyterlab/notebook-extension@workspace:packages/notebook-extension, @jupyterlab/notebook-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/notebook-extension@workspace:packages/notebook-extension" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/completer": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/docmanager-extension": ^4.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/filebrowser": ^4.0.8 + "@jupyterlab/launcher": ^4.0.8 + "@jupyterlab/logconsole": ^4.0.8 + "@jupyterlab/lsp": ^4.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/metadataform": ^4.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/property-inspector": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@rjsf/utils": ^5.1.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/notebook@^4.0.8, @jupyterlab/notebook@workspace:packages/notebook": + version: 0.0.0-use.local + resolution: "@jupyterlab/notebook@workspace:packages/notebook" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/cells": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/codemirror": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/documentsearch": ^4.0.8 + "@jupyterlab/lsp": ^4.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/dragdrop": ^2.1.3 + "@lumino/messaging": ^2.0.1 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/observables@^5.0.8, @jupyterlab/observables@workspace:packages/observables": + version: 0.0.0-use.local + resolution: "@jupyterlab/observables@workspace:packages/observables" + dependencies: + "@jupyterlab/testing": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/outputarea@^4.0.8, @jupyterlab/outputarea@workspace:packages/outputarea": + version: 0.0.0-use.local + resolution: "@jupyterlab/outputarea@workspace:packages/outputarea" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/pdf-extension@^4.0.8, @jupyterlab/pdf-extension@workspace:packages/pdf-extension, @jupyterlab/pdf-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/pdf-extension@workspace:packages/pdf-extension" + dependencies: + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/property-inspector@^4.0.8, @jupyterlab/property-inspector@workspace:packages/property-inspector": + version: 0.0.0-use.local + resolution: "@jupyterlab/property-inspector@workspace:packages/property-inspector" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/rendermime-extension@^4.0.8, @jupyterlab/rendermime-extension@workspace:packages/rendermime-extension, @jupyterlab/rendermime-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/rendermime-extension@workspace:packages/rendermime-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/docmanager": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/rendermime-interfaces@^3.8.8, @jupyterlab/rendermime-interfaces@workspace:packages/rendermime-interfaces": + version: 0.0.0-use.local + resolution: "@jupyterlab/rendermime-interfaces@workspace:packages/rendermime-interfaces" + dependencies: + "@lumino/coreutils": ^1.11.0 || ^2.1.2 + "@lumino/widgets": ^1.37.2 || ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/rendermime@^4.0.8, @jupyterlab/rendermime@workspace:packages/rendermime": + version: 0.0.0-use.local + resolution: "@jupyterlab/rendermime@workspace:packages/rendermime" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + "@types/lodash.escape": ^4.0.6 + fs-extra: ^10.1.0 + jest: ^29.2.0 + lodash.escape: ^4.0.1 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/repo-top@workspace:.": + version: 0.0.0-use.local + resolution: "@jupyterlab/repo-top@workspace:." + dependencies: + "@typescript-eslint/eslint-plugin": ~5.55.0 + "@typescript-eslint/parser": ~5.55.0 + eslint: ~8.36.0 + eslint-config-prettier: ~8.7.0 + eslint-plugin-jest: ~27.2.1 + eslint-plugin-prettier: ~5.0.0 + eslint-plugin-react: ~7.32.2 + lerna: ^7.1.4 + prettier: ~3.0.0 + stylelint: ^15.10.1 + stylelint-config-prettier: ^9.0.3 + stylelint-config-recommended: ^13.0.0 + stylelint-config-standard: ^34.0.0 + stylelint-csstree-validator: ^3.0.0 + stylelint-prettier: ^4.0.0 + typedoc: ~0.24.7 + typedoc-plugin-mdn-links: ^3.0.3 + languageName: unknown + linkType: soft + +"@jupyterlab/running-extension@^4.0.8, @jupyterlab/running-extension@workspace:packages/running-extension, @jupyterlab/running-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/running-extension@workspace:packages/running-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/running": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/commands": ^2.1.3 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/running@^4.0.8, @jupyterlab/running@workspace:packages/running": + version: 0.0.0-use.local + resolution: "@jupyterlab/running@workspace:packages/running" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/services@^7.0.8, @jupyterlab/services@workspace:packages/services": + version: 0.0.0-use.local + resolution: "@jupyterlab/services@workspace:packages/services" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/polling": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@types/jest": ^29.2.0 + "@types/ws": ^8.5.3 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + webpack: ^5.76.1 + webpack-cli: ^5.0.1 + ws: ^8.11.0 + languageName: unknown + linkType: soft + +"@jupyterlab/settingeditor-extension@^4.0.8, @jupyterlab/settingeditor-extension@workspace:packages/settingeditor-extension, @jupyterlab/settingeditor-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/settingeditor-extension@workspace:packages/settingeditor-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/settingeditor": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/disposable": ^2.1.2 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/settingeditor@^4.0.8, @jupyterlab/settingeditor@workspace:packages/settingeditor": + version: 0.0.0-use.local + resolution: "@jupyterlab/settingeditor@workspace:packages/settingeditor" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/inspector": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@rjsf/core": ^5.1.0 + "@rjsf/utils": ^5.1.0 + "@rjsf/validator-ajv8": ^5.1.0 + "@types/jest": ^29.2.0 + "@types/react": ^18.0.26 + "@types/react-test-renderer": ^18.0.0 + jest: ^29.2.0 + json-schema: ^0.4.0 + react: ^18.2.0 + react-test-renderer: ^18.2.0 + rimraf: ~3.0.0 + ts-jest: ^29.1.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/settingregistry@^4.0.8, @jupyterlab/settingregistry@workspace:packages/settingregistry": + version: 0.0.0-use.local + resolution: "@jupyterlab/settingregistry@workspace:packages/settingregistry" + dependencies: + "@jupyterlab/nbformat": ^4.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@rjsf/utils": ^5.1.0 + "@types/jest": ^29.2.0 + ajv: ^8.12.0 + jest: ^29.2.0 + json5: ^2.2.3 + rimraf: ~3.0.0 + typescript: ~5.0.4 + peerDependencies: + react: ">=16" + languageName: unknown + linkType: soft + +"@jupyterlab/shortcuts-extension@^4.0.8, @jupyterlab/shortcuts-extension@workspace:packages/shortcuts-extension, @jupyterlab/shortcuts-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/shortcuts-extension@workspace:packages/shortcuts-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/keyboard": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/statedb@^4.0.8, @jupyterlab/statedb@workspace:packages/statedb": + version: 0.0.0-use.local + resolution: "@jupyterlab/statedb@workspace:packages/statedb" + dependencies: + "@jupyterlab/testing": ^4.0.8 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/statusbar-extension@^4.0.8, @jupyterlab/statusbar-extension@workspace:packages/statusbar-extension, @jupyterlab/statusbar-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/statusbar-extension@workspace:packages/statusbar-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/statusbar": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@types/react": ^18.0.26 + "@types/react-dom": ^18.0.9 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/statusbar@^4.0.8, @jupyterlab/statusbar@workspace:packages/statusbar": + version: 0.0.0-use.local + resolution: "@jupyterlab/statusbar@workspace:packages/statusbar" + dependencies: + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/template@workspace:buildutils/template": + version: 0.0.0-use.local + resolution: "@jupyterlab/template@workspace:buildutils/template" + dependencies: + "@jupyterlab/testing": ^4.0.8 + "@types/jest": ^29.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/terminal-extension@^4.0.8, @jupyterlab/terminal-extension@workspace:packages/terminal-extension, @jupyterlab/terminal-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/terminal-extension@workspace:packages/terminal-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/launcher": ^4.0.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/running": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/terminal": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/widgets": ^2.3.0 + "@types/webpack-env": ^1.18.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/terminal@^4.0.8, @jupyterlab/terminal@workspace:packages/terminal": + version: 0.0.0-use.local + resolution: "@jupyterlab/terminal@workspace:packages/terminal" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/messaging": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + canvas: ^2.11.2 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + xterm: ~5.1.0 + xterm-addon-canvas: ~0.3.0 + xterm-addon-fit: ~0.7.0 + xterm-addon-web-links: ~0.8.0 + xterm-addon-webgl: ~0.14.0 + languageName: unknown + linkType: soft + +"@jupyterlab/testing@^4.0.8, @jupyterlab/testing@workspace:packages/testing": + version: 0.0.0-use.local + resolution: "@jupyterlab/testing@workspace:packages/testing" + dependencies: + "@babel/core": ^7.10.2 + "@babel/preset-env": ^7.10.2 + "@jupyterlab/coreutils": ^6.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@types/jest": ^29.2.0 + "@types/node": ^18.11.18 + "@types/node-fetch": ^2.6.2 + child_process: ~1.0.2 + deepmerge: ^4.2.2 + fs-extra: ^10.1.0 + identity-obj-proxy: ^3.0.0 + jest: ^29.2.0 + jest-environment-jsdom: ^29.3.0 + jest-junit: ^15.0.0 + node-fetch: ^2.6.0 + rimraf: ~3.0.0 + simulate-event: ~1.4.0 + ts-jest: ^29.1.0 + typescript: ~5.0.4 + peerDependencies: + typescript: ">=4.3" + languageName: unknown + linkType: soft + +"@jupyterlab/testutils@^4.0.8, @jupyterlab/testutils@workspace:testutils": + version: 0.0.0-use.local + resolution: "@jupyterlab/testutils@workspace:testutils" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/theme-dark-extension@^4.0.8, @jupyterlab/theme-dark-extension@workspace:packages/theme-dark-extension, @jupyterlab/theme-dark-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/theme-dark-extension@workspace:packages/theme-dark-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/translation": ^4.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/theme-light-extension@^4.0.8, @jupyterlab/theme-light-extension@workspace:packages/theme-light-extension, @jupyterlab/theme-light-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/theme-light-extension@workspace:packages/theme-light-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/translation": ^4.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/toc-extension@^6.0.8, @jupyterlab/toc-extension@workspace:packages/toc-extension, @jupyterlab/toc-extension@~6.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/toc-extension@workspace:packages/toc-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/toc": ^6.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/toc@^6.0.8, @jupyterlab/toc@workspace:packages/toc": + version: 0.0.0-use.local + resolution: "@jupyterlab/toc@workspace:packages/toc" + dependencies: + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/docregistry": ^4.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + "@types/react": ^18.0.26 + jest: ^29.2.0 + react: ^18.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/tooltip-extension@^4.0.8, @jupyterlab/tooltip-extension@workspace:packages/tooltip-extension, @jupyterlab/tooltip-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/tooltip-extension@workspace:packages/tooltip-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/console": ^4.0.8 + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/fileeditor": ^4.0.8 + "@jupyterlab/notebook": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/tooltip": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/tooltip@^4.0.8, @jupyterlab/tooltip@workspace:packages/tooltip": + version: 0.0.0-use.local + resolution: "@jupyterlab/tooltip@workspace:packages/tooltip" + dependencies: + "@jupyterlab/codeeditor": ^4.0.8 + "@jupyterlab/rendermime": ^4.0.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/ui-components": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/widgets": ^2.3.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/translation-extension@^4.0.8, @jupyterlab/translation-extension@workspace:packages/translation-extension, @jupyterlab/translation-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/translation-extension@workspace:packages/translation-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/apputils": ^4.1.8 + "@jupyterlab/mainmenu": ^4.0.8 + "@jupyterlab/settingregistry": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/translation@^4.0.8, @jupyterlab/translation@workspace:packages/translation": + version: 0.0.0-use.local + resolution: "@jupyterlab/translation@workspace:packages/translation" + dependencies: + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/services": ^7.0.8 + "@jupyterlab/statedb": ^4.0.8 + "@jupyterlab/testing": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@types/jest": ^29.2.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/ui-components-extension@^4.0.8, @jupyterlab/ui-components-extension@workspace:packages/ui-components-extension, @jupyterlab/ui-components-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/ui-components-extension@workspace:packages/ui-components-extension" + dependencies: + "@jupyterlab/application": ^4.0.8 + "@jupyterlab/ui-components": ^4.0.8 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + languageName: unknown + linkType: soft + +"@jupyterlab/ui-components@^4.0.8, @jupyterlab/ui-components@workspace:packages/ui-components": + version: 0.0.0-use.local + resolution: "@jupyterlab/ui-components@workspace:packages/ui-components" + dependencies: + "@jupyterlab/coreutils": ^6.0.8 + "@jupyterlab/observables": ^5.0.8 + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/testing": ^4.0.8 + "@jupyterlab/translation": ^4.0.8 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@rjsf/core": ^5.1.0 + "@rjsf/utils": ^5.1.0 + "@types/jest": ^29.2.0 + "@types/react": ^18.0.26 + jest: ^29.2.0 + react: ^18.2.0 + react-dom: ^18.2.0 + rimraf: ~3.0.0 + svgo: ^3.0.1 + typedoc: ~0.24.7 + typescript: ~5.0.4 + typestyle: ^2.0.4 + peerDependencies: + react: ^18.2.0 + languageName: unknown + linkType: soft + +"@jupyterlab/vega5-extension@^4.0.8, @jupyterlab/vega5-extension@workspace:packages/vega5-extension, @jupyterlab/vega5-extension@~4.0.8": + version: 0.0.0-use.local + resolution: "@jupyterlab/vega5-extension@workspace:packages/vega5-extension" + dependencies: + "@jupyterlab/rendermime-interfaces": ^3.8.8 + "@jupyterlab/testutils": ^4.0.8 + "@lumino/coreutils": ^2.1.2 + "@lumino/widgets": ^2.3.0 + "@types/jest": ^29.2.0 + "@types/webpack-env": ^1.18.0 + jest: ^29.2.0 + rimraf: ~3.0.0 + typedoc: ~0.24.7 + typescript: ~5.0.4 + vega: ^5.20.0 + vega-embed: ^6.2.1 + vega-lite: ^5.6.1-next.1 + languageName: unknown + linkType: soft + +"@lerna/child-process@npm:7.1.4": + version: 7.1.4 + resolution: "@lerna/child-process@npm:7.1.4" + dependencies: + chalk: ^4.1.0 + execa: ^5.0.0 + strong-log-transformer: ^2.1.0 + checksum: faac89a6c0b2eb205688fdf4307ce7fd06ee60b0c10f45e159c257cebcdb02a1bd048682ec56d3fa8c52d3f4e0b5d9113a6f419a0b040da70b1eba5aea2a3945 + languageName: node + linkType: hard + +"@lerna/create@npm:7.1.4": + version: 7.1.4 + resolution: "@lerna/create@npm:7.1.4" + dependencies: + "@lerna/child-process": 7.1.4 + dedent: 0.7.0 + fs-extra: ^11.1.1 + init-package-json: 5.0.0 + npm-package-arg: 8.1.1 + p-reduce: ^2.1.0 + pacote: ^15.2.0 + pify: 5.0.0 + semver: ^7.3.4 + slash: ^3.0.0 + validate-npm-package-license: ^3.0.4 + validate-npm-package-name: 5.0.0 + yargs-parser: 20.2.4 + checksum: e826bc5cf07d8e2ddf100a96bb8f39f2ee907343c91e0a111e03bd02fc03c62b783686fb7497dfcf7ae95cb6448e3bff07f5b4b3419d1bd7069a8bb15572b1d1 + languageName: node + linkType: hard + +"@lezer/common@npm:^1.0.0, @lezer/common@npm:^1.0.2": + version: 1.0.2 + resolution: "@lezer/common@npm:1.0.2" + checksum: bbcc58e07be02652bf0700d2856042ec089d5be0b95893d628b3e18192ade864fac83b61b19653e10b9f1472261a178b12318d934e9004edd5483a577c0db56b + languageName: node + linkType: hard + +"@lezer/cpp@npm:^1.0.0": + version: 1.1.0 + resolution: "@lezer/cpp@npm:1.1.0" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 9b25c881fc9b64fd2b019a077a85b0ba7cfda0bbdd92dbb0ff43300c9ba1ec4360128fe912bfe0f06a1c1bb5a564c5ace375c8aad254d07a717768a8f268695d + languageName: node + linkType: hard + +"@lezer/css@npm:^1.0.0, @lezer/css@npm:^1.1.0": + version: 1.1.1 + resolution: "@lezer/css@npm:1.1.1" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: a7e4893aacaa7f26d5679c77a640f401b37d14155cb54863aa91b59dfd220b280360a341c0fedafc65d31101de13a5ae33cf3876c352f2da528344dafdc9b3d7 + languageName: node + linkType: hard + +"@lezer/generator@npm:^1.2.2": + version: 1.2.2 + resolution: "@lezer/generator@npm:1.2.2" + dependencies: + "@lezer/common": ^1.0.2 + "@lezer/lr": ^1.3.0 + bin: + lezer-generator: dist/lezer-generator.cjs + checksum: 62f93704d7b0b53bbd842c65552b9089f354edbf5f50f05d65a214a5dba05c0a63c898ca448a93ecc803d5b8b05d5eb593a5e5509c478c8dfa3b49ff28dcafb3 + languageName: node + linkType: hard + +"@lezer/highlight@npm:^1.0.0, @lezer/highlight@npm:^1.1.3, @lezer/highlight@npm:^1.1.4": + version: 1.1.4 + resolution: "@lezer/highlight@npm:1.1.4" + dependencies: + "@lezer/common": ^1.0.0 + checksum: 30e848c02839bfcd9472fcd6e74d71cba12379cef38f27d0c6cab0e6831f92150cfc629d267a40cc31f84cf46ac0a935400163fdf931b2672c516bec29417485 + languageName: node + linkType: hard + +"@lezer/html@npm:^1.3.0": + version: 1.3.3 + resolution: "@lezer/html@npm:1.3.3" + dependencies: + "@lezer/common": ^1.0.0 + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: ad74a5a751daead9d5979a4e1dc55faf94e623672d6b835e4d84d7a1174f326fa6b511a354f6dd5ec4c0b375242614966607ecf07cc92e5c13afe882178fe01d + languageName: node + linkType: hard + +"@lezer/java@npm:^1.0.0": + version: 1.0.3 + resolution: "@lezer/java@npm:1.0.3" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 2fffea6627d130413ffad4e61040267974cca3167d98881b9e5b5e2455530de74a82c234d93603e92a4972fad314671453c49c0a76b0f4547c4617d671fd7b99 + languageName: node + linkType: hard + +"@lezer/javascript@npm:^1.0.0": + version: 1.4.1 + resolution: "@lezer/javascript@npm:1.4.1" + dependencies: + "@lezer/highlight": ^1.1.3 + "@lezer/lr": ^1.3.0 + checksum: 634270116d5f1c278e2949d397845f41cac388dec7f0db593a3dc23e0fd4a1b73b9bf08f96fcf109fcd3d38c4b374d48676dce3261ff8ff83a85f5d6a37989f7 + languageName: node + linkType: hard + +"@lezer/json@npm:^1.0.0": + version: 1.0.0 + resolution: "@lezer/json@npm:1.0.0" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: c1ca0cdf681415b58a383a669944bed66da3aa830870d32d1e471d545cff0fe43d9ac8a0d2a318a96daa99cd5a645b1d58ba8fbdd2e8d7ca4d33a62c7582cbab + languageName: node + linkType: hard + +"@lezer/lr@npm:^1.0.0, @lezer/lr@npm:^1.1.0, @lezer/lr@npm:^1.3.0, @lezer/lr@npm:^1.3.3": + version: 1.3.3 + resolution: "@lezer/lr@npm:1.3.3" + dependencies: + "@lezer/common": ^1.0.0 + checksum: 1804074c794005a31c54d80ab72127f19ae5be29bb627c52bc001a57b1af97a9e62732ff13e3aeb7bc53b330202b6bd3747272c64d87f257dbba533e75a183a3 + languageName: node + linkType: hard + +"@lezer/markdown@npm:^1.0.0, @lezer/markdown@npm:^1.0.2": + version: 1.0.2 + resolution: "@lezer/markdown@npm:1.0.2" + dependencies: + "@lezer/common": ^1.0.0 + "@lezer/highlight": ^1.0.0 + checksum: c4bbfcd8a5a9d924a7cf2b5e5e99c78e7705473cc59804070278b5cfcf478af9dd567025d0926cbf03e3ea6abb8f173425220d3107c05a2d7e0ca3fe3d5c92ef + languageName: node + linkType: hard + +"@lezer/php@npm:^1.0.0": + version: 1.0.1 + resolution: "@lezer/php@npm:1.0.1" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.1.0 + checksum: a847c255c030b4d38913ddf1d5bd7324d83be7ef8d1d244542870be03b9bf7dc71283afeb2415c40dfd188cb99f0cc44bad760b5f3b7c35c3b8e5e00253848fc + languageName: node + linkType: hard + +"@lezer/python@npm:^1.1.4": + version: 1.1.7 + resolution: "@lezer/python@npm:1.1.7" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 7ae6b4ae770b3cd849eee3d8fb1d904745aee202a76e7db0a079725a97571c4778fa5bd74878206e44aa3349044bf056008e19e7a90650fad93d51890f685077 + languageName: node + linkType: hard + +"@lezer/rust@npm:^1.0.0": + version: 1.0.0 + resolution: "@lezer/rust@npm:1.0.0" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 0c42f415674f60ca2ef4274b446577621cdeec8f31168b1c3b90888a4377c513f02a89ee346421c264ec3a77fe2fa3e134996be6463ed506dbbc79b4b4505375 + languageName: node + linkType: hard + +"@lezer/xml@npm:^1.0.0": + version: 1.0.1 + resolution: "@lezer/xml@npm:1.0.1" + dependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 271319aa7802c123845b70ffa63d7065c0f92fc6a1ddb1f8ec9f3aa965bca3df3c9fad4d4de53187ddf230e833cd3ab3a84cb2aded76ab5f6831e9a2fc310923 + languageName: node + linkType: hard + +"@lumino/algorithm@npm:^2.0.1": + version: 2.0.1 + resolution: "@lumino/algorithm@npm:2.0.1" + checksum: cbf7fcf6ee6b785ea502cdfddc53d61f9d353dcb9659343511d5cd4b4030be2ff2ca4c08daec42f84417ab0318a3d9972a17319fa5231693e109ab112dcf8000 + languageName: node + linkType: hard + +"@lumino/application@npm:^2.2.1": + version: 2.2.1 + resolution: "@lumino/application@npm:2.2.1" + dependencies: + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/widgets": ^2.3.0 + checksum: a33e661703728440bc7d2ddb4674261f4de0d20eb8c9846646cbd6debac03b5c65e78d739a500903550fd83b8f47b47fa82ec178c97bc9967ca3ac4014075cde + languageName: node + linkType: hard + +"@lumino/collections@npm:^2.0.1": + version: 2.0.1 + resolution: "@lumino/collections@npm:2.0.1" + dependencies: + "@lumino/algorithm": ^2.0.1 + checksum: 8a29b7973a388a33c5beda0819dcd2dc2aad51a8406dcfd4581b055a9f77a39dc5800f7a8b4ae3c0bb97ae7b56a7a869e2560ffb7a920a28e93b477ba05907d6 + languageName: node + linkType: hard + +"@lumino/commands@npm:^2.1.3": + version: 2.1.3 + resolution: "@lumino/commands@npm:2.1.3" + dependencies: + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/keyboard": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + checksum: e4e3ee279f2a5e8d68e4ce142c880333f5542f90c684972402356936ecb5cf5e07163800b59e7cb8c911cbdb4e5089edcc5dd2990bc8db10c87517268de1fc5d + languageName: node + linkType: hard + +"@lumino/coreutils@npm:^1.11.0 || ^2.0.0, @lumino/coreutils@npm:^1.11.0 || ^2.1.2, @lumino/coreutils@npm:^2.1.2": + version: 2.1.2 + resolution: "@lumino/coreutils@npm:2.1.2" + checksum: 7865317ac0676b448d108eb57ab5d8b2a17c101995c0f7a7106662d9fe6c859570104525f83ee3cda12ae2e326803372206d6f4c1f415a5b59e4158a7b81066f + languageName: node + linkType: hard + +"@lumino/datagrid@npm:^2.2.0": + version: 2.2.0 + resolution: "@lumino/datagrid@npm:2.2.0" + dependencies: + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/dragdrop": ^2.1.3 + "@lumino/keyboard": ^2.0.1 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + checksum: dcd6e06500c05b0f30b9924a25a2cc4c1cb98b8432f488148e74e98a7fe092a1f19cadbdc9edfbede9e2030d30b84e5633e40753fbe8d6bbb120d3336d3675ff + languageName: node + linkType: hard + +"@lumino/disposable@npm:^1.10.0 || ^2.0.0, @lumino/disposable@npm:^2.1.2": + version: 2.1.2 + resolution: "@lumino/disposable@npm:2.1.2" + dependencies: + "@lumino/signaling": ^2.1.2 + checksum: ac2fb2bf18d0b2939fda454f3db248a0ff6e8a77b401e586d1caa9293b3318f808b93a117c9c3ac27cd17aab545aea83b49108d099b9b2f5503ae2a012fbc6e2 + languageName: node + linkType: hard + +"@lumino/domutils@npm:^2.0.1": + version: 2.0.1 + resolution: "@lumino/domutils@npm:2.0.1" + checksum: 61fa0ab226869dfbb763fc426790cf5a43b7d6f4cea1364c6dd56d61c44bff05eea188d33ff847449608ef58ed343161bee15c19b96f35410e4ee35815dc611a + languageName: node + linkType: hard + +"@lumino/dragdrop@npm:^2.1.3": + version: 2.1.3 + resolution: "@lumino/dragdrop@npm:2.1.3" + dependencies: + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + checksum: d5f7eb4cc9f9a084cb9af10f02d6741b25d683350878ecbc324e24ba9d4b5246451a410e2ca5fff227aab1c191d1e73a2faf431f93e13111d67a4e426e126258 + languageName: node + linkType: hard + +"@lumino/keyboard@npm:^2.0.1": + version: 2.0.1 + resolution: "@lumino/keyboard@npm:2.0.1" + checksum: cf33f13427a418efd7cc91061233321e860d5404f3d86397781028309bef86c8ad2d88276ffe335c1db0fe619bd9d1e60641c81f881696957a58703ee4652c3e + languageName: node + linkType: hard + +"@lumino/messaging@npm:^2.0.1": + version: 2.0.1 + resolution: "@lumino/messaging@npm:2.0.1" + dependencies: + "@lumino/algorithm": ^2.0.1 + "@lumino/collections": ^2.0.1 + checksum: 964c4651c374b17452b4252b7d71500b32d2ecd87c192fc5bcf5d3bd1070661d78d07edcac8eca7d1d6fd50aa25992505485e1296d6dd995691b8e349b652045 + languageName: node + linkType: hard + +"@lumino/polling@npm:^2.1.2": + version: 2.1.2 + resolution: "@lumino/polling@npm:2.1.2" + dependencies: + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + checksum: fa9b401e6dbeb8f31d7e3ba485e8ef1e0c92b3f2da086239c0ed49931026f5d3528709193c93e031e35ac624fb4bbbfcdcbaa0e25eb797f36e2952e5cd91e9e3 + languageName: node + linkType: hard + +"@lumino/properties@npm:^2.0.1": + version: 2.0.1 + resolution: "@lumino/properties@npm:2.0.1" + checksum: c50173a935148cc4148fdaea119df1d323ee004ae16ab666800388d27e9730345629662d85f25591683329b39f0cdae60ee8c94e8943b4d0ef7d7370a38128d6 + languageName: node + linkType: hard + +"@lumino/signaling@npm:^1.10.0 || ^2.0.0, @lumino/signaling@npm:^2.1.2": + version: 2.1.2 + resolution: "@lumino/signaling@npm:2.1.2" + dependencies: + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + checksum: ad7d7153db57980da899c43e412e6130316ef30b231a70250e7af49058db16cadb018c1417a2ea8083d83c48623cfe6b705fa82bf10216b1a8949aed9f4aca4e + languageName: node + linkType: hard + +"@lumino/virtualdom@npm:^2.0.1": + version: 2.0.1 + resolution: "@lumino/virtualdom@npm:2.0.1" + dependencies: + "@lumino/algorithm": ^2.0.1 + checksum: cf59b6f15b430e13e9e657b7a0619b9056cd9ea7b2a87f407391d071c501b77403c302b6a66dca510382045e75b2e3fe551630bb391f1c6b33678057d4bec164 + languageName: node + linkType: hard + +"@lumino/widgets@npm:^1.37.2 || ^2.3.0, @lumino/widgets@npm:^2.3.0": + version: 2.3.0 + resolution: "@lumino/widgets@npm:2.3.0" + dependencies: + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/dragdrop": ^2.1.3 + "@lumino/keyboard": ^2.0.1 + "@lumino/messaging": ^2.0.1 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + checksum: a8559bd3574b7fc16e7679e05994c515b0d3e78dada35786d161f67c639941d134e92ce31d95c2e4ac06709cdf83b0e7fb4b6414a3f7779579222a2fb525d025 + languageName: node + linkType: hard + +"@mapbox/node-pre-gyp@npm:^1.0.0": + version: 1.0.10 + resolution: "@mapbox/node-pre-gyp@npm:1.0.10" + dependencies: + detect-libc: ^2.0.0 + https-proxy-agent: ^5.0.0 + make-dir: ^3.1.0 + node-fetch: ^2.6.7 + nopt: ^5.0.0 + npmlog: ^5.0.1 + rimraf: ^3.0.2 + semver: ^7.3.5 + tar: ^6.1.11 + bin: + node-pre-gyp: bin/node-pre-gyp + checksum: 1a98db05d955b74dad3814679593df293b9194853698f3f5f1ed00ecd93128cdd4b14fb8767fe44ac6981ef05c23effcfdc88710e7c1de99ccb6f647890597c8 + languageName: node + linkType: hard + +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" + dependencies: + "@nodelib/fs.stat": 2.0.5 + run-parallel: ^1.1.9 + checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 + languageName: node + linkType: hard + +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 + languageName: node + linkType: hard + +"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" + dependencies: + "@nodelib/fs.scandir": 2.1.5 + fastq: ^1.6.0 + checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^2.1.0": + version: 2.1.2 + resolution: "@npmcli/fs@npm:2.1.2" + dependencies: + "@gar/promisify": ^1.1.3 + semver: ^7.3.5 + checksum: 405074965e72d4c9d728931b64d2d38e6ea12066d4fad651ac253d175e413c06fe4350970c783db0d749181da8fe49c42d3880bd1cbc12cd68e3a7964d820225 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^3.1.0": + version: 3.1.0 + resolution: "@npmcli/fs@npm:3.1.0" + dependencies: + semver: ^7.3.5 + checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e + languageName: node + linkType: hard + +"@npmcli/git@npm:^4.0.0": + version: 4.1.0 + resolution: "@npmcli/git@npm:4.1.0" + dependencies: + "@npmcli/promise-spawn": ^6.0.0 + lru-cache: ^7.4.4 + npm-pick-manifest: ^8.0.0 + proc-log: ^3.0.0 + promise-inflight: ^1.0.1 + promise-retry: ^2.0.1 + semver: ^7.3.5 + which: ^3.0.0 + checksum: 37efb926593f294eb263297cdfffec9141234f977b89a7a6b95ff7a72576c1d7f053f4961bc4b5e79dea6476fe08e0f3c1ed9e4aeb84169e357ff757a6a70073 + languageName: node + linkType: hard + +"@npmcli/installed-package-contents@npm:^2.0.1": + version: 2.0.2 + resolution: "@npmcli/installed-package-contents@npm:2.0.2" + dependencies: + npm-bundled: ^3.0.0 + npm-normalize-package-bin: ^3.0.0 + bin: + installed-package-contents: lib/index.js + checksum: 60789d5ed209ee5df479232f62d9d38ecec36e95701cae88320b828b8651351b32d7b47d16d4c36cc7ce5000db4bf1f3e6981bed6381bdc5687ff4bc0795682d + languageName: node + linkType: hard + +"@npmcli/move-file@npm:^2.0.0": + version: 2.0.1 + resolution: "@npmcli/move-file@npm:2.0.1" + dependencies: + mkdirp: ^1.0.4 + rimraf: ^3.0.2 + checksum: 52dc02259d98da517fae4cb3a0a3850227bdae4939dda1980b788a7670636ca2b4a01b58df03dd5f65c1e3cb70c50fa8ce5762b582b3f499ec30ee5ce1fd9380 + languageName: node + linkType: hard + +"@npmcli/node-gyp@npm:^3.0.0": + version: 3.0.0 + resolution: "@npmcli/node-gyp@npm:3.0.0" + checksum: fe3802b813eecb4ade7ad77c9396cb56721664275faab027e3bd8a5e15adfbbe39e2ecc19f7885feb3cfa009b96632741cc81caf7850ba74440c6a2eee7b4ffc + languageName: node + linkType: hard + +"@npmcli/promise-spawn@npm:^6.0.0, @npmcli/promise-spawn@npm:^6.0.1": + version: 6.0.2 + resolution: "@npmcli/promise-spawn@npm:6.0.2" + dependencies: + which: ^3.0.0 + checksum: aa725780c13e1f97ab32ed7bcb5a207a3fb988e1d7ecdc3d22a549a22c8034740366b351c4dde4b011bcffcd8c4a7be6083d9cf7bc7e897b88837150de018528 + languageName: node + linkType: hard + +"@npmcli/run-script@npm:6.0.2, @npmcli/run-script@npm:^6.0.0": + version: 6.0.2 + resolution: "@npmcli/run-script@npm:6.0.2" + dependencies: + "@npmcli/node-gyp": ^3.0.0 + "@npmcli/promise-spawn": ^6.0.0 + node-gyp: ^9.0.0 + read-package-json-fast: ^3.0.0 + which: ^3.0.0 + checksum: 7a671d7dbeae376496e1c6242f02384928617dc66cd22881b2387272205c3668f8490ec2da4ad63e1abf979efdd2bdf4ea0926601d78578e07d83cfb233b3a1a + languageName: node + linkType: hard + +"@nrwl/devkit@npm:16.5.2": + version: 16.5.2 + resolution: "@nrwl/devkit@npm:16.5.2" + dependencies: + "@nx/devkit": 16.5.2 + checksum: 6fc2185b5d1010d5307c544329164a2c5e9c2940d38b984b11e7e54eff0c4bfe3661571823ebdaa2002697f4e1cededa55e066337642f2396034960258380acb + languageName: node + linkType: hard + +"@nrwl/tao@npm:16.5.2": + version: 16.5.2 + resolution: "@nrwl/tao@npm:16.5.2" + dependencies: + nx: 16.5.2 + bin: + tao: index.js + checksum: 3721fe1a1ce24936e413a0bd6c02fbdf53cdbfc490de80d6a360220cbb47cae4edca5d7efe5e74daf2d9d4a53983c13c50c6b18415c01e3257a8b7a8ce1cdda1 + languageName: node + linkType: hard + +"@nx/devkit@npm:16.5.2, @nx/devkit@npm:>=16.5.1 < 17": + version: 16.5.2 + resolution: "@nx/devkit@npm:16.5.2" + dependencies: + "@nrwl/devkit": 16.5.2 + ejs: ^3.1.7 + ignore: ^5.0.4 + semver: 7.5.3 + tmp: ~0.2.1 + tslib: ^2.3.0 + peerDependencies: + nx: ">= 15 <= 17" + checksum: 5271031faddce2a4a695f3acba706298d7831ccfe4dc4460cf7200e74bbfdc46ebf3d0daca5ca619432c9f754dffad5c31c1cc2e9180693d06ea7fab80285c4a + languageName: node + linkType: hard + +"@nx/nx-darwin-arm64@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-darwin-arm64@npm:16.5.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@nx/nx-darwin-x64@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-darwin-x64@npm:16.5.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@nx/nx-freebsd-x64@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-freebsd-x64@npm:16.5.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@nx/nx-linux-arm-gnueabihf@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-linux-arm-gnueabihf@npm:16.5.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@nx/nx-linux-arm64-gnu@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-linux-arm64-gnu@npm:16.5.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@nx/nx-linux-arm64-musl@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-linux-arm64-musl@npm:16.5.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@nx/nx-linux-x64-gnu@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-linux-x64-gnu@npm:16.5.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@nx/nx-linux-x64-musl@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-linux-x64-musl@npm:16.5.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@nx/nx-win32-arm64-msvc@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-win32-arm64-msvc@npm:16.5.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@nx/nx-win32-x64-msvc@npm:16.5.2": + version: 16.5.2 + resolution: "@nx/nx-win32-x64-msvc@npm:16.5.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@octokit/auth-token@npm:^3.0.0": + version: 3.0.3 + resolution: "@octokit/auth-token@npm:3.0.3" + dependencies: + "@octokit/types": ^9.0.0 + checksum: 9b3f569cec1b7e0aa88ab6da68aed4b49b6652261bd957257541fabaf6a4d4ed99f908153cc3dd2fe15b8b0ccaff8caaafaa50bb1a4de3925b0954a47cca1900 + languageName: node + linkType: hard + +"@octokit/core@npm:^4.2.1": + version: 4.2.4 + resolution: "@octokit/core@npm:4.2.4" + dependencies: + "@octokit/auth-token": ^3.0.0 + "@octokit/graphql": ^5.0.0 + "@octokit/request": ^6.0.0 + "@octokit/request-error": ^3.0.0 + "@octokit/types": ^9.0.0 + before-after-hook: ^2.2.0 + universal-user-agent: ^6.0.0 + checksum: ac8ab47440a31b0228a034aacac6994b64d6b073ad5b688b4c5157fc5ee0d1af1c926e6087bf17fd7244ee9c5998839da89065a90819bde4a97cb77d4edf58a6 + languageName: node + linkType: hard + +"@octokit/endpoint@npm:^7.0.0": + version: 7.0.5 + resolution: "@octokit/endpoint@npm:7.0.5" + dependencies: + "@octokit/types": ^9.0.0 + is-plain-object: ^5.0.0 + universal-user-agent: ^6.0.0 + checksum: 81c9e9eabf50e48940cceff7c4d7fbc9327190296507cfe8a199ea00cd492caf8f18a841caf4e3619828924b481996eb16091826db6b5a649bee44c8718ecaa9 + languageName: node + linkType: hard + +"@octokit/graphql@npm:^5.0.0": + version: 5.0.5 + resolution: "@octokit/graphql@npm:5.0.5" + dependencies: + "@octokit/request": ^6.0.0 + "@octokit/types": ^9.0.0 + universal-user-agent: ^6.0.0 + checksum: eb2d1a6305a3d1f55ff0ce92fb88b677f0bb789757152d58a79ef61171fb65ecf6fe18d6c27e236c0cee6a0c2600c2cb8370f5ac7184f8e9361c085aa4555bb1 + languageName: node + linkType: hard + +"@octokit/openapi-types@npm:^18.0.0": + version: 18.0.0 + resolution: "@octokit/openapi-types@npm:18.0.0" + checksum: d487d6c6c1965e583eee417d567e4fe3357a98953fc49bce1a88487e7908e9b5dbb3e98f60dfa340e23b1792725fbc006295aea071c5667a813b9c098185b56f + languageName: node + linkType: hard + +"@octokit/plugin-enterprise-rest@npm:6.0.1": + version: 6.0.1 + resolution: "@octokit/plugin-enterprise-rest@npm:6.0.1" + checksum: 1c9720002f31daf62f4f48e73557dcdd7fcde6e0f6d43256e3f2ec827b5548417297186c361fb1af497fdcc93075a7b681e6ff06e2f20e4a8a3e74cc09d1f7e3 + languageName: node + linkType: hard + +"@octokit/plugin-paginate-rest@npm:^6.1.2": + version: 6.1.2 + resolution: "@octokit/plugin-paginate-rest@npm:6.1.2" + dependencies: + "@octokit/tsconfig": ^1.0.2 + "@octokit/types": ^9.2.3 + peerDependencies: + "@octokit/core": ">=4" + checksum: a7b3e686c7cbd27ec07871cde6e0b1dc96337afbcef426bbe3067152a17b535abd480db1861ca28c88d93db5f7bfdbcadd0919ead19818c28a69d0e194038065 + languageName: node + linkType: hard + +"@octokit/plugin-request-log@npm:^1.0.4": + version: 1.0.4 + resolution: "@octokit/plugin-request-log@npm:1.0.4" + peerDependencies: + "@octokit/core": ">=3" + checksum: 2086db00056aee0f8ebd79797b5b57149ae1014e757ea08985b71eec8c3d85dbb54533f4fd34b6b9ecaa760904ae6a7536be27d71e50a3782ab47809094bfc0c + languageName: node + linkType: hard + +"@octokit/plugin-rest-endpoint-methods@npm:^7.1.2": + version: 7.2.3 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:7.2.3" + dependencies: + "@octokit/types": ^10.0.0 + peerDependencies: + "@octokit/core": ">=3" + checksum: 21dfb98514dbe900c29cddb13b335bbce43d613800c6b17eba3c1fd31d17e69c1960f3067f7bf864bb38fdd5043391f4a23edee42729d8c7fbabd00569a80336 + languageName: node + linkType: hard + +"@octokit/request-error@npm:^3.0.0": + version: 3.0.3 + resolution: "@octokit/request-error@npm:3.0.3" + dependencies: + "@octokit/types": ^9.0.0 + deprecation: ^2.0.0 + once: ^1.4.0 + checksum: 5db0b514732686b627e6ed9ef1ccdbc10501f1b271a9b31f784783f01beee70083d7edcfeb35fbd7e569fa31fdd6762b1ff6b46101700d2d97e7e48e749520d0 + languageName: node + linkType: hard + +"@octokit/request@npm:^6.0.0": + version: 6.2.3 + resolution: "@octokit/request@npm:6.2.3" + dependencies: + "@octokit/endpoint": ^7.0.0 + "@octokit/request-error": ^3.0.0 + "@octokit/types": ^9.0.0 + is-plain-object: ^5.0.0 + node-fetch: ^2.6.7 + universal-user-agent: ^6.0.0 + checksum: fef4097be8375d20bb0b3276d8a3adf866ec628f2b0664d334f3c29b92157da847899497abdc7a5be540053819b55564990543175ad48f04e9e6f25f0395d4d3 + languageName: node + linkType: hard + +"@octokit/rest@npm:19.0.11": + version: 19.0.11 + resolution: "@octokit/rest@npm:19.0.11" + dependencies: + "@octokit/core": ^4.2.1 + "@octokit/plugin-paginate-rest": ^6.1.2 + "@octokit/plugin-request-log": ^1.0.4 + "@octokit/plugin-rest-endpoint-methods": ^7.1.2 + checksum: 147518ad51d214ead88adc717b5fdc4f33317949d58c124f4069bdf07d2e6b49fa66861036b9e233aed71fcb88ff367a6da0357653484e466175ab4fb7183b3b + languageName: node + linkType: hard + +"@octokit/tsconfig@npm:^1.0.2": + version: 1.0.2 + resolution: "@octokit/tsconfig@npm:1.0.2" + checksum: 74d56f3e9f326a8dd63700e9a51a7c75487180629c7a68bbafee97c612fbf57af8347369bfa6610b9268a3e8b833c19c1e4beb03f26db9a9dce31f6f7a19b5b1 + languageName: node + linkType: hard + +"@octokit/types@npm:^10.0.0": + version: 10.0.0 + resolution: "@octokit/types@npm:10.0.0" + dependencies: + "@octokit/openapi-types": ^18.0.0 + checksum: 8aafba2ff0cd2435fb70c291bf75ed071c0fa8a865cf6169648732068a35dec7b85a345851f18920ec5f3e94ee0e954988485caac0da09ec3f6781cc44fe153a + languageName: node + linkType: hard + +"@octokit/types@npm:^9.0.0, @octokit/types@npm:^9.2.3": + version: 9.3.2 + resolution: "@octokit/types@npm:9.3.2" + dependencies: + "@octokit/openapi-types": ^18.0.0 + checksum: f55d096aaed3e04b8308d4422104fb888f355988056ba7b7ef0a4c397b8a3e54290d7827b06774dbe0c9ce55280b00db486286954f9c265aa6b03091026d9da8 + languageName: node + linkType: hard + +"@parcel/watcher@npm:2.0.4": + version: 2.0.4 + resolution: "@parcel/watcher@npm:2.0.4" + dependencies: + node-addon-api: ^3.2.1 + node-gyp: latest + node-gyp-build: ^4.3.0 + checksum: 890bdc69a52942791b276caa2cd65ef816576d6b5ada91aa28cf302b35d567c801dafe167f2525dcb313f5b420986ea11bd56228dd7ddde1116944d8f924a0a1 + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f + languageName: node + linkType: hard + +"@pkgr/utils@npm:^2.3.1": + version: 2.4.2 + resolution: "@pkgr/utils@npm:2.4.2" + dependencies: + cross-spawn: ^7.0.3 + fast-glob: ^3.3.0 + is-glob: ^4.0.3 + open: ^9.1.0 + picocolors: ^1.0.0 + tslib: ^2.6.0 + checksum: 24e04c121269317d259614cd32beea3af38277151c4002df5883c4be920b8e3490bb897748e844f9d46bf68230f86dabd4e8f093773130e7e60529a769a132fc + languageName: node + linkType: hard + +"@playwright/test@npm:^1.32.2": + version: 1.32.2 + resolution: "@playwright/test@npm:1.32.2" + dependencies: + "@types/node": "*" + fsevents: 2.3.2 + playwright-core: 1.32.2 + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: 3e4a9286c2a63c12b55368c3b94e8817fee15146e09e5be549be21d6938b6bcd26a32b0dc295100a3b24f1f0839fdb65be680e7a11a39014f485f36551c6844a + languageName: node + linkType: hard + +"@polka/url@npm:^1.0.0-next.20": + version: 1.0.0-next.21 + resolution: "@polka/url@npm:1.0.0-next.21" + checksum: c7654046d38984257dd639eab3dc770d1b0340916097b2fac03ce5d23506ada684e05574a69b255c32ea6a144a957c8cd84264159b545fca031c772289d88788 + languageName: node + linkType: hard + +"@rjsf/core@npm:^5.1.0": + version: 5.2.1 + resolution: "@rjsf/core@npm:5.2.1" + dependencies: + lodash: ^4.17.15 + lodash-es: ^4.17.15 + markdown-to-jsx: ^7.1.9 + nanoid: ^3.3.4 + prop-types: ^15.7.2 + peerDependencies: + "@rjsf/utils": ^5.0.0 + react: ^16.14.0 || >=17 + checksum: 0a4033a6d6d8a1d05b8b3f1ae635713d6a39c143467311fb5d775360bd55ad77dd33c67de4358d80bd445010f99573e4aff97d0e4f99d6d83a55b96edafe00c8 + languageName: node + linkType: hard + +"@rjsf/utils@npm:^5.1.0": + version: 5.2.1 + resolution: "@rjsf/utils@npm:5.2.1" + dependencies: + json-schema-merge-allof: ^0.8.1 + jsonpointer: ^5.0.1 + lodash: ^4.17.15 + lodash-es: ^4.17.15 + react-is: ^18.2.0 + peerDependencies: + react: ^16.14.0 || >=17 + checksum: e40703246b94878a981f003c08867eac7f9c08eec8d45c17d13a282998e942379f507600b7f7a44a94005970ce48f24527e30da802869e41e67becdb4aa9a242 + languageName: node + linkType: hard + +"@rjsf/validator-ajv8@npm:^5.1.0": + version: 5.2.1 + resolution: "@rjsf/validator-ajv8@npm:5.2.1" + dependencies: + ajv: ^8.12.0 + ajv-formats: ^2.1.1 + lodash: ^4.17.15 + lodash-es: ^4.17.15 + peerDependencies: + "@rjsf/utils": ^5.0.0 + checksum: a9dc303e252c57fc66c26709b8ed9744ae51bb64c962d62086894bab725a891ae399269cc10da57aa8a659cb5468ae6aeb1c4199f338fae681b5e12bcfa94ee7 + languageName: node + linkType: hard + +"@sigstore/protobuf-specs@npm:^0.1.0": + version: 0.1.0 + resolution: "@sigstore/protobuf-specs@npm:0.1.0" + checksum: 9959bc5176906609dda6ad2a1f5226fac1e49fcb4d29f38969d2a2e3a05cba8e2479721ba78c46a507513abacb63f25a991e5e8856c300204cded455f34ba8c5 + languageName: node + linkType: hard + +"@sigstore/tuf@npm:^1.0.0": + version: 1.0.0 + resolution: "@sigstore/tuf@npm:1.0.0" + dependencies: + "@sigstore/protobuf-specs": ^0.1.0 + make-fetch-happen: ^11.0.1 + tuf-js: ^1.1.3 + checksum: f1bbcb689ba22d31f6eefd06588864b83e346fddb93a11235f5fd8076d8fd88a9f6001eb2118f54babfea9e38474994afc14dac0c961e8d51bfd4970b4b633e4 + languageName: node + linkType: hard + +"@sinclair/typebox@npm:^0.25.16": + version: 0.25.24 + resolution: "@sinclair/typebox@npm:0.25.24" + checksum: 10219c58f40b8414c50b483b0550445e9710d4fe7b2c4dccb9b66533dd90ba8e024acc776026cebe81e87f06fa24b07fdd7bc30dd277eb9cc386ec50151a3026 + languageName: node + linkType: hard + +"@sindresorhus/is@npm:^4.0.0": + version: 4.6.0 + resolution: "@sindresorhus/is@npm:4.6.0" + checksum: 83839f13da2c29d55c97abc3bc2c55b250d33a0447554997a85c539e058e57b8da092da396e252b11ec24a0279a0bed1f537fa26302209327060643e327f81d2 + languageName: node + linkType: hard + +"@sinonjs/commons@npm:^2.0.0": + version: 2.0.0 + resolution: "@sinonjs/commons@npm:2.0.0" + dependencies: + type-detect: 4.0.8 + checksum: 5023ba17edf2b85ed58262313b8e9b59e23c6860681a9af0200f239fe939e2b79736d04a260e8270ddd57196851dde3ba754d7230be5c5234e777ae2ca8af137 + languageName: node + linkType: hard + +"@sinonjs/fake-timers@npm:^10.0.2": + version: 10.0.2 + resolution: "@sinonjs/fake-timers@npm:10.0.2" + dependencies: + "@sinonjs/commons": ^2.0.0 + checksum: c62aa98e7cefda8dedc101ce227abc888dc46b8ff9706c5f0a8dfd9c3ada97d0a5611384738d9ba0b26b59f99c2ba24efece8e779bb08329e9e87358fa309824 + languageName: node + linkType: hard + +"@stdlib/array@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/array@npm:0.0.12" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/blas": ^0.0.x + "@stdlib/complex": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/symbol": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 0d95690461f0c4560eabef0796d1170274415cd03de80333c6d39814d0484a6873ef4be04a64941ebf3a600747e84c3a4f23b21c7020e53842c07985331b39f1 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/assert@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/assert@npm:0.0.12" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/complex": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/fs": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/ndarray": ^0.0.x + "@stdlib/number": ^0.0.x + "@stdlib/os": ^0.0.x + "@stdlib/process": ^0.0.x + "@stdlib/regexp": ^0.0.x + "@stdlib/streams": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/symbol": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: d4dcbeabbfb86ba56cdd972ff785f43e7d25018b2b1800cab8b0deb9e5c54c795d6ead3d142f4dd13c351f636deba4dc1857c85147d6b059fdc78eb2c9510b99 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/bigint@npm:^0.0.x": + version: 0.0.11 + resolution: "@stdlib/bigint@npm:0.0.11" + dependencies: + "@stdlib/utils": ^0.0.x + checksum: 7bf825d116e4b010e214209af239706ac1ef923eecb5c8b0af9229c9975450081355e441ecc7b4765d81a9e653141868e0492b8061d1e65724fa42fb8283aabd + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/blas@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/blas@npm:0.0.12" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/number": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 67ea00a968f7a9c710b37f718b7f756e2830e479a1a1ee44cbf6ec3cc27dd8863078928867707d9d1624007e81de89d040f2326d10f435e2cce913cab121975e + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/buffer@npm:^0.0.x": + version: 0.0.11 + resolution: "@stdlib/buffer@npm:0.0.11" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/process": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 93df02e3bf548e940ff9cef65121566e7bf93b554f0614d62336c9dbccfc07c9f1b1c4e9a7aebbe4819ef16a6d2a33a7010c2fdf908fface8298a3109c3c4ef0 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/cli@npm:^0.0.x": + version: 0.0.10 + resolution: "@stdlib/cli@npm:0.0.10" + dependencies: + "@stdlib/utils": ^0.0.x + minimist: ^1.2.0 + checksum: bbece8d3dbff2835518582a7726c6c4c22743dc408d2303d9e35a3b72151d5d0a8e78d61bc896663d4c3fb702e966abea7a1bd621ed943723a359f57053f121f + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/complex@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/complex@npm:0.0.12" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 8eda35027495417f1b0dd9bbbc2d4983f50ad3cf9e2276ffe0945ccdbe78f0fc66b9fc36ab71926d2a125c8fb7467c8970a222b230b42ff4bb8042c53314ca09 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/constants@npm:^0.0.x": + version: 0.0.11 + resolution: "@stdlib/constants@npm:0.0.11" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/number": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: fc19d055a4e71ae84b6c92e4a3a88371d50693da8f0a813df4063dc549374d19b9cf23f4fdae2fb7b2013e13929f713c3e1b9e4054767e741b75561ed43d15c3 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/fs@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/fs@npm:0.0.12" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/process": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/utils": ^0.0.x + debug: ^2.6.9 + checksum: 33ac5ee4844d4599fe3a8a8402f1a3e2cafee31a5c9cf5b85df530a61a2b54ef17dc30a67be98dacdc2958219413edd0e4cdc3c28266f4bc30277ee024f6a49e + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/math@npm:^0.0.x": + version: 0.0.11 + resolution: "@stdlib/math@npm:0.0.11" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/ndarray": ^0.0.x + "@stdlib/number": ^0.0.x + "@stdlib/strided": ^0.0.x + "@stdlib/symbol": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + debug: ^2.6.9 + checksum: 6c4c9dda36fbce50553e1437354c5286aa782c42399534dbed8e696ddeb1b91ef6cff5fe5962f1c9e1eb2ef63c63d9bd58f7ca4b87d59018aaac20099c3fb79a + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/ndarray@npm:^0.0.x": + version: 0.0.13 + resolution: "@stdlib/ndarray@npm:0.0.13" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/bigint": ^0.0.x + "@stdlib/buffer": ^0.0.x + "@stdlib/complex": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/number": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 842a94afce5fc74bf8a964b75a302ddb8713eadbc79616e6799f1310c8bce860ed9e9877adc4a39338d9136b8798947ee21cf03368d46408308a313c8075d49a + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/nlp@npm:^0.0.x": + version: 0.0.11 + resolution: "@stdlib/nlp@npm:0.0.11" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/random": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 398fe2853fb95404bb6598e3e199ca3e0435b94447d50e14e2e30582cadfb91f43464f23d80a0e1da4d64567a4a108a7299d7440509f1ab26b02aea7bb16e9a8 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/number@npm:^0.0.x": + version: 0.0.10 + resolution: "@stdlib/number@npm:0.0.10" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/os": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 326190956c787cbf9321c332beedab5ba4b3fa97d52a82aa708a0349b4678c0df7a351424f00a606f4eaca4fb4ba4cc191580c99d7c64ee0f08d37baa3de14f2 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/os@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/os@npm:0.0.12" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/fs": ^0.0.x + "@stdlib/process": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 37156b0c723da70d7740d92d08fc592eae803461c1d546cff6ac044765d6e40722fdad342219277e747c39344b513096ac1d0aa1e733cf3079bd8a9a8578612a + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/process@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/process@npm:0.0.12" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/buffer": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/fs": ^0.0.x + "@stdlib/streams": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 6d5c3d943f9914d1ae39bd36ad7436f783cf64baa2bff67a808035c99258676ae3f704c328a78d62754951cf85fe99d8e9af5f4fa7d5f8cba347bca72767e357 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/random@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/random@npm:0.0.12" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/blas": ^0.0.x + "@stdlib/buffer": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/fs": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/process": ^0.0.x + "@stdlib/stats": ^0.0.x + "@stdlib/streams": ^0.0.x + "@stdlib/symbol": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + debug: ^2.6.9 + readable-stream: ^2.1.4 + checksum: 67fcb5553274f8596ceae91153e96ae297bacfd55279821cb09f19f2844845aaf892802e4a5962965323dbfded0c7df8a89a6ce77d60d5c8a5899d483055a964 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/regexp@npm:^0.0.x": + version: 0.0.13 + resolution: "@stdlib/regexp@npm:0.0.13" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: dd52adb096ff9a02d1c4818be2889ae01bc04a0cdbc0d52473685e0a7a4eaa13e1be603b964f140f7488d11450b644dc5f8c97029d77db1ed4a563554245ff1c + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/stats@npm:^0.0.x, @stdlib/stats@npm:~0.0.13": + version: 0.0.13 + resolution: "@stdlib/stats@npm:0.0.13" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/blas": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/ndarray": ^0.0.x + "@stdlib/random": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/symbol": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 5ca12b2e123543f56a59aca828e14afaf525ad4aa40467bee7037a9178e21e55d4ce8ba3de9387cc9a0efe3e0d035d6c58705b12f634f77a2b3f87d334dfb076 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/streams@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/streams@npm:0.0.12" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/buffer": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/fs": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + debug: ^2.6.9 + readable-stream: ^2.1.4 + checksum: 231b4607d082ea81d9dadbeab08002ec398a29c7eb5d611d8a4183f9db6964428e2f8a9e0f8edd085ca12b5d58258576987a575e9d8f6fcabcb5a62c6b8efe88 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/strided@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/strided@npm:0.0.12" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/ndarray": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 55ccc8543596894a2e3ad734b394700c69697b499a54b3bfbcf80cddd8d91509792c23931f5cebf7c89269676ac3f44352582e4f42e2c2c2898363cc3a76403d + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/string@npm:^0.0.x": + version: 0.0.14 + resolution: "@stdlib/string@npm:0.0.14" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/fs": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/nlp": ^0.0.x + "@stdlib/process": ^0.0.x + "@stdlib/regexp": ^0.0.x + "@stdlib/streams": ^0.0.x + "@stdlib/types": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: aaaaaddf381cccc67f15dbab76f43ce81cb71a4f5595bfa06ef915b6747458deca3c25c60ff3c002c0c36482687d92a150f364069559dfea915f63a040d5f603 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/symbol@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/symbol@npm:0.0.12" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 2263341ce0296de2063d26038902bd63bf1d7b820307402fdf38c3b248bd026f17d96bccdc3189fd9fcc9c83a778eaab797dc11805bd66203b8ac9c6934f6588 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/time@npm:^0.0.x": + version: 0.0.14 + resolution: "@stdlib/time@npm:0.0.14" + dependencies: + "@stdlib/assert": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/fs": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/utils": ^0.0.x + checksum: 6e8a1b985a09936ab09c98d44bf1b2c79e08995c3c73401494bc1f6f708747ef136d769af4809a8af92a9ceb3d390db6c4c4e01608cd8d794a86c4b57e343eb1 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/types@npm:^0.0.x": + version: 0.0.14 + resolution: "@stdlib/types@npm:0.0.14" + checksum: 5680a655ddb3ad730f5c7eb2363a43e089f3e6a1b85b12546cab49f7749bb3baf293bd50fbfe55486f233f4227f1020b65eb461b754b94fb4a4bc2799647ec22 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@stdlib/utils@npm:^0.0.x": + version: 0.0.12 + resolution: "@stdlib/utils@npm:0.0.12" + dependencies: + "@stdlib/array": ^0.0.x + "@stdlib/assert": ^0.0.x + "@stdlib/blas": ^0.0.x + "@stdlib/buffer": ^0.0.x + "@stdlib/cli": ^0.0.x + "@stdlib/constants": ^0.0.x + "@stdlib/fs": ^0.0.x + "@stdlib/math": ^0.0.x + "@stdlib/os": ^0.0.x + "@stdlib/process": ^0.0.x + "@stdlib/random": ^0.0.x + "@stdlib/regexp": ^0.0.x + "@stdlib/streams": ^0.0.x + "@stdlib/string": ^0.0.x + "@stdlib/symbol": ^0.0.x + "@stdlib/time": ^0.0.x + "@stdlib/types": ^0.0.x + debug: ^2.6.9 + checksum: e0c3671c5f62c11bb3abd721f2958c41641b00a75d449bd25fbb62bcb8689cfe9c1f600c0688e7b6819ae870d6e5974d0fc7b2ec86081c45d9194b316b2a2ec2 + conditions: (os=aix | os=darwin | os=freebsd | os=linux | os=macos | os=openbsd | os=sunos | os=win32 | os=windows) + languageName: node + linkType: hard + +"@szmarczak/http-timer@npm:^4.0.5": + version: 4.0.6 + resolution: "@szmarczak/http-timer@npm:4.0.6" + dependencies: + defer-to-connect: ^2.0.0 + checksum: c29df3bcec6fc3bdec2b17981d89d9c9fc9bd7d0c9bcfe92821dc533f4440bc890ccde79971838b4ceed1921d456973c4180d7175ee1d0023ad0562240a58d95 + languageName: node + linkType: hard + +"@tootallnate/once@npm:2": + version: 2.0.0 + resolution: "@tootallnate/once@npm:2.0.0" + checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 + languageName: node + linkType: hard + +"@trysound/sax@npm:0.2.0": + version: 0.2.0 + resolution: "@trysound/sax@npm:0.2.0" + checksum: 11226c39b52b391719a2a92e10183e4260d9651f86edced166da1d95f39a0a1eaa470e44d14ac685ccd6d3df7e2002433782872c0feeb260d61e80f21250e65c + languageName: node + linkType: hard + +"@tufjs/canonical-json@npm:1.0.0": + version: 1.0.0 + resolution: "@tufjs/canonical-json@npm:1.0.0" + checksum: 9ff3bcd12988fb23643690da3e009f9130b7b10974f8e7af4bd8ad230a228119de8609aa76d75264fe80f152b50872dea6ea53def69534436a4c24b4fcf6a447 + languageName: node + linkType: hard + +"@tufjs/models@npm:1.0.4": + version: 1.0.4 + resolution: "@tufjs/models@npm:1.0.4" + dependencies: + "@tufjs/canonical-json": 1.0.0 + minimatch: ^9.0.0 + checksum: b489baa854abce6865f360591c20d5eb7d8dde3fb150f42840c12bb7ee3e5e7a69eab9b2e44ea82ae1f8cd95b586963c5a5c5af8ba4ffa3614b3ddccbc306779 + languageName: node + linkType: hard + +"@types/babel__core@npm:^7.1.14": + version: 7.20.0 + resolution: "@types/babel__core@npm:7.20.0" + dependencies: + "@babel/parser": ^7.20.7 + "@babel/types": ^7.20.7 + "@types/babel__generator": "*" + "@types/babel__template": "*" + "@types/babel__traverse": "*" + checksum: 49b601a0a7637f1f387442c8156bd086cfd10ff4b82b0e1994e73a6396643b5435366fb33d6b604eade8467cca594ef97adcbc412aede90bb112ebe88d0ad6df + languageName: node + linkType: hard + +"@types/babel__generator@npm:*": + version: 7.6.4 + resolution: "@types/babel__generator@npm:7.6.4" + dependencies: + "@babel/types": ^7.0.0 + checksum: 20effbbb5f8a3a0211e95959d06ae70c097fb6191011b73b38fe86deebefad8e09ee014605e0fd3cdaedc73d158be555866810e9166e1f09e4cfd880b874dcb0 + languageName: node + linkType: hard + +"@types/babel__template@npm:*": + version: 7.4.1 + resolution: "@types/babel__template@npm:7.4.1" + dependencies: + "@babel/parser": ^7.1.0 + "@babel/types": ^7.0.0 + checksum: 649fe8b42c2876be1fd28c6ed9b276f78152d5904ec290b6c861d9ef324206e0a5c242e8305c421ac52ecf6358fa7e32ab7a692f55370484825c1df29b1596ee + languageName: node + linkType: hard + +"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": + version: 7.18.3 + resolution: "@types/babel__traverse@npm:7.18.3" + dependencies: + "@babel/types": ^7.3.0 + checksum: d20953338b2f012ab7750932ece0a78e7d1645b0a6ff42d49be90f55e9998085da1374a9786a7da252df89555c6586695ba4d1d4b4e88ab2b9f306bcd35e00d3 + languageName: node + linkType: hard + +"@types/base16@npm:^1.0.2": + version: 1.0.2 + resolution: "@types/base16@npm:1.0.2" + checksum: 5bc587d45066dae6fb14a4a7f72e57044fa1a8057eed86d4005f9e38a0c38b83009828ac3072e6e9e4be1cf5d5032849690adf8cd51efd545fa281bee5cf0fa5 + languageName: node + linkType: hard + +"@types/braces@npm:*": + version: 3.0.2 + resolution: "@types/braces@npm:3.0.2" + checksum: 0b1bee5e8332fabf57397de8dec1a24c3bf53efc3284d15d64d7dd67c0ba9853e0191e5220464ff171a4963c1db2b0cfd3926e2b363a95909ff723a4426a1964 + languageName: node + linkType: hard + +"@types/cacheable-request@npm:^6.0.1": + version: 6.0.3 + resolution: "@types/cacheable-request@npm:6.0.3" + dependencies: + "@types/http-cache-semantics": "*" + "@types/keyv": ^3.1.4 + "@types/node": "*" + "@types/responselike": ^1.0.0 + checksum: d9b26403fe65ce6b0cb3720b7030104c352bcb37e4fac2a7089a25a97de59c355fa08940658751f2f347a8512aa9d18fdb66ab3ade835975b2f454f2d5befbd9 + languageName: node + linkType: hard + +"@types/clone@npm:~2.1.1": + version: 2.1.1 + resolution: "@types/clone@npm:2.1.1" + checksum: bda9668b9d6e0875d64bbe00763676f566e8647bc224333a03ac7fd66655dfed56a98a9f8304d0145c4411b964649c84c4d1a03adbdb6547eafb9ab8f303d254 + languageName: node + linkType: hard + +"@types/emscripten@npm:^1.39.6": + version: 1.39.7 + resolution: "@types/emscripten@npm:1.39.7" + checksum: 9871e4495358cc06cc45b2798022cd097d8ac2eb5b2fae7c276c6c5cadea05507150fad053c73ed346d4cbd844c50a3438604e5d7c3c2a7446b703cacb1ce172 + languageName: node + linkType: hard + +"@types/eslint-scope@npm:^3.7.3": + version: 3.7.4 + resolution: "@types/eslint-scope@npm:3.7.4" + dependencies: + "@types/eslint": "*" + "@types/estree": "*" + checksum: ea6a9363e92f301cd3888194469f9ec9d0021fe0a397a97a6dd689e7545c75de0bd2153dfb13d3ab532853a278b6572c6f678ce846980669e41029d205653460 + languageName: node + linkType: hard + +"@types/eslint@npm:*": + version: 8.21.1 + resolution: "@types/eslint@npm:8.21.1" + dependencies: + "@types/estree": "*" + "@types/json-schema": "*" + checksum: 584068441e4000c7b41c8928274fdcc737bc62f564928c30eb64ec41bbdbac31612f9fedaf490bceab31ec8305e99615166428188ea345d58878394683086fae + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:^1.0.0": + version: 1.0.0 + resolution: "@types/estree@npm:1.0.0" + checksum: 910d97fb7092c6738d30a7430ae4786a38542023c6302b95d46f49420b797f21619cdde11fa92b338366268795884111c2eb10356e4bd2c8ad5b92941e9e6443 + languageName: node + linkType: hard + +"@types/estree@npm:^0.0.51": + version: 0.0.51 + resolution: "@types/estree@npm:0.0.51" + checksum: e56a3bcf759fd9185e992e7fdb3c6a5f81e8ff120e871641607581fb3728d16c811702a7d40fa5f869b7f7b4437ab6a87eb8d98ffafeee51e85bbe955932a189 + languageName: node + linkType: hard + +"@types/fs-extra@npm:^9.0.1": + version: 9.0.13 + resolution: "@types/fs-extra@npm:9.0.13" + dependencies: + "@types/node": "*" + checksum: add79e212acd5ac76b97b9045834e03a7996aef60a814185e0459088fd290519a3c1620865d588fa36c4498bf614210d2a703af5cf80aa1dbc125db78f6edac3 + languageName: node + linkType: hard + +"@types/geojson@npm:^7946.0.10": + version: 7946.0.10 + resolution: "@types/geojson@npm:7946.0.10" + checksum: 12c407c2dc93ecb26c08af533ee732f1506a9b29456616ba7ba1d525df96206c28ddf44a528f6a5415d7d22893e9d967420940a9c095ee5e539c1eba5fefc1f4 + languageName: node + linkType: hard + +"@types/glob@npm:^7.1.1": + version: 7.2.0 + resolution: "@types/glob@npm:7.2.0" + dependencies: + "@types/minimatch": "*" + "@types/node": "*" + checksum: 6ae717fedfdfdad25f3d5a568323926c64f52ef35897bcac8aca8e19bc50c0bd84630bbd063e5d52078b2137d8e7d3c26eabebd1a2f03ff350fff8a91e79fc19 + languageName: node + linkType: hard + +"@types/graceful-fs@npm:^4.1.3": + version: 4.1.6 + resolution: "@types/graceful-fs@npm:4.1.6" + dependencies: + "@types/node": "*" + checksum: c3070ccdc9ca0f40df747bced1c96c71a61992d6f7c767e8fd24bb6a3c2de26e8b84135ede000b7e79db530a23e7e88dcd9db60eee6395d0f4ce1dae91369dd4 + languageName: node + linkType: hard + +"@types/html-minifier-terser@npm:^6.0.0": + version: 6.1.0 + resolution: "@types/html-minifier-terser@npm:6.1.0" + checksum: eb843f6a8d662d44fb18ec61041117734c6aae77aa38df1be3b4712e8e50ffaa35f1e1c92fdd0fde14a5675fecf457abcd0d15a01fae7506c91926176967f452 + languageName: node + linkType: hard + +"@types/http-cache-semantics@npm:*": + version: 4.0.1 + resolution: "@types/http-cache-semantics@npm:4.0.1" + checksum: 1048aacf627829f0d5f00184e16548205cd9f964bf0841c29b36bc504509230c40bc57c39778703a1c965a6f5b416ae2cbf4c1d4589c889d2838dd9dbfccf6e9 + languageName: node + linkType: hard + +"@types/inquirer@npm:^9.0.3": + version: 9.0.3 + resolution: "@types/inquirer@npm:9.0.3" + dependencies: + "@types/through": "*" + rxjs: ^7.2.0 + checksum: 729a0deefddf95434090d8f6adc120c6de4a023cefd63fb1c3b1d1cfd1abbef4caef87af47589cdbeb16177037e48a0ffc397c39e845d2b7b5dd820eb7b80862 + languageName: node + linkType: hard + +"@types/is-glob@npm:^4.0.1": + version: 4.0.2 + resolution: "@types/is-glob@npm:4.0.2" + checksum: 50b0a52b6d179781b36bfce35155e1e0dc66b62e2943153d7d7c7079c40ba6236528a254de8be6c52ff9a7a351996887802efd7fd763da3e2121315e4ffe2edf + languageName: node + linkType: hard + +"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": + version: 2.0.4 + resolution: "@types/istanbul-lib-coverage@npm:2.0.4" + checksum: a25d7589ee65c94d31464c16b72a9dc81dfa0bea9d3e105ae03882d616e2a0712a9c101a599ec482d297c3591e16336962878cb3eb1a0a62d5b76d277a890ce7 + languageName: node + linkType: hard + +"@types/istanbul-lib-report@npm:*": + version: 3.0.0 + resolution: "@types/istanbul-lib-report@npm:3.0.0" + dependencies: + "@types/istanbul-lib-coverage": "*" + checksum: 656398b62dc288e1b5226f8880af98087233cdb90100655c989a09f3052b5775bf98ba58a16c5ae642fb66c61aba402e07a9f2bff1d1569e3b306026c59f3f36 + languageName: node + linkType: hard + +"@types/istanbul-reports@npm:^3.0.0": + version: 3.0.1 + resolution: "@types/istanbul-reports@npm:3.0.1" + dependencies: + "@types/istanbul-lib-report": "*" + checksum: f1ad54bc68f37f60b30c7915886b92f86b847033e597f9b34f2415acdbe5ed742fa559a0a40050d74cdba3b6a63c342cac1f3a64dba5b68b66a6941f4abd7903 + languageName: node + linkType: hard + +"@types/jest@npm:^29.2.0": + version: 29.4.0 + resolution: "@types/jest@npm:29.4.0" + dependencies: + expect: ^29.0.0 + pretty-format: ^29.0.0 + checksum: 23760282362a252e6690314584d83a47512d4cd61663e957ed3398ecf98195fe931c45606ee2f9def12f8ed7d8aa102d492ec42d26facdaf8b78094a31e6568e + languageName: node + linkType: hard + +"@types/jsdom@npm:^20.0.0": + version: 20.0.1 + resolution: "@types/jsdom@npm:20.0.1" + dependencies: + "@types/node": "*" + "@types/tough-cookie": "*" + parse5: ^7.0.0 + checksum: d55402c5256ef451f93a6e3d3881f98339fe73a5ac2030588df056d6835df8367b5a857b48d27528289057e26dcdd3f502edc00cb877c79174cb3a4c7f2198c1 + languageName: node + linkType: hard + +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.3, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": + version: 7.0.11 + resolution: "@types/json-schema@npm:7.0.11" + checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d + languageName: node + linkType: hard + +"@types/keyv@npm:^3.1.4": + version: 3.1.4 + resolution: "@types/keyv@npm:3.1.4" + dependencies: + "@types/node": "*" + checksum: e009a2bfb50e90ca9b7c6e8f648f8464067271fd99116f881073fa6fa76dc8d0133181dd65e6614d5fb1220d671d67b0124aef7d97dc02d7e342ab143a47779d + languageName: node + linkType: hard + +"@types/lodash.escape@npm:^4.0.6": + version: 4.0.7 + resolution: "@types/lodash.escape@npm:4.0.7" + dependencies: + "@types/lodash": "*" + checksum: 777c54bf2331f1433f302f58364ba68d5214896085d8b4bbeb4a1d330c0df22ed7352ea77b9a96149ef2fbc77f6146579e7f4e0f64485bac2c768e04e652bbf9 + languageName: node + linkType: hard + +"@types/lodash.mergewith@npm:^4.6.1": + version: 4.6.7 + resolution: "@types/lodash.mergewith@npm:4.6.7" + dependencies: + "@types/lodash": "*" + checksum: 71e86dfd3f6058213f102b5f11087976c042709003e9ef1d62bf29363b8c2608c130bb8804ec8d54b2bfd9f1fae8bcf5478db602b36884022550c6dcfd7d69ab + languageName: node + linkType: hard + +"@types/lodash@npm:*, @types/lodash@npm:^4.14.175, @types/lodash@npm:^4.14.178, @types/lodash@npm:^4.14.191": + version: 4.14.191 + resolution: "@types/lodash@npm:4.14.191" + checksum: ba0d5434e10690869f32d5ea49095250157cae502f10d57de0a723fd72229ce6c6a4979576f0f13e0aa9fbe3ce2457bfb9fa7d4ec3d6daba56730a51906d1491 + languageName: node + linkType: hard + +"@types/marked@npm:^4.0.3": + version: 4.0.8 + resolution: "@types/marked@npm:4.0.8" + checksum: 68278fa7acaa5d920cdc239d675b5daf842e0ad4779e4848cd617d9baf2ac1afccb5a264c331e37d80031d647e1640cb983cd31e73d45b28552670b4853fad8e + languageName: node + linkType: hard + +"@types/micromatch@npm:^4.0.1": + version: 4.0.2 + resolution: "@types/micromatch@npm:4.0.2" + dependencies: + "@types/braces": "*" + checksum: 6c678e9c625d5b422c6d2c1001da1c502ecc4457248343bbd324b79fd798a6563e336a4d79630d80e8202312013dd7cf8b4440afa644d04477abd26fde6fba24 + languageName: node + linkType: hard + +"@types/minimatch@npm:*, @types/minimatch@npm:^3.0.3": + version: 3.0.5 + resolution: "@types/minimatch@npm:3.0.5" + checksum: c41d136f67231c3131cf1d4ca0b06687f4a322918a3a5adddc87ce90ed9dbd175a3610adee36b106ae68c0b92c637c35e02b58c8a56c424f71d30993ea220b92 + languageName: node + linkType: hard + +"@types/minimist@npm:^1.2.0, @types/minimist@npm:^1.2.2": + version: 1.2.2 + resolution: "@types/minimist@npm:1.2.2" + checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d + languageName: node + linkType: hard + +"@types/mkdirp@npm:^0.5.2": + version: 0.5.2 + resolution: "@types/mkdirp@npm:0.5.2" + dependencies: + "@types/node": "*" + checksum: 21e6681ee18cee6314dbe0f57ada48981912b76de8266f438ba2573770d60aaa8dd376baad3f20e2346696a7cca84b0aadd1737222341553a0091831a46e6ad1 + languageName: node + linkType: hard + +"@types/node-fetch@npm:^2.6.2": + version: 2.6.2 + resolution: "@types/node-fetch@npm:2.6.2" + dependencies: + "@types/node": "*" + form-data: ^3.0.0 + checksum: 6f73b1470000d303d25a6fb92875ea837a216656cb7474f66cdd67bb014aa81a5a11e7ac9c21fe19bee9ecb2ef87c1962bceeaec31386119d1ac86e4c30ad7a6 + languageName: node + linkType: hard + +"@types/node@npm:*, @types/node@npm:^18.11.18": + version: 18.15.0 + resolution: "@types/node@npm:18.15.0" + checksum: d81372276dd5053b1743338b61a2178ff9722dc609189d01fc7d1c2acd539414039e0e4780678730514390dad3f29c366a28c29e8dbd5b0025651181f6dd6669 + languageName: node + linkType: hard + +"@types/node@npm:^13.7.0": + version: 13.13.52 + resolution: "@types/node@npm:13.13.52" + checksum: 8f1afff497ebeba209e2dc340d823284e087a47632afe99a7daa30eaff80893e520f222ad400cd1f2d3b8288e93cf3eaded52a8e64eaefb8aacfe6c35de98f42 + languageName: node + linkType: hard + +"@types/normalize-package-data@npm:^2.4.0": + version: 2.4.1 + resolution: "@types/normalize-package-data@npm:2.4.1" + checksum: e87bccbf11f95035c89a132b52b79ce69a1e3652fe55962363063c9c0dae0fe2477ebc585e03a9652adc6f381d24ba5589cc5e51849df4ced3d3e004a7d40ed5 + languageName: node + linkType: hard + +"@types/prettier@npm:^1.16.1": + version: 1.19.1 + resolution: "@types/prettier@npm:1.19.1" + checksum: d34229c37d3419b01efa31968b68c33b8b9b717bdf961e48f68e89821864b1329c45323d28e1200a204e7b2eefca1dabdac4aa0c3d698dbc8c60247322103b11 + languageName: node + linkType: hard + +"@types/prettier@npm:^2.1.5, @types/prettier@npm:~2.6.0": + version: 2.6.4 + resolution: "@types/prettier@npm:2.6.4" + checksum: a8ec6601cbacf8040782cc883bf1a9393fdcb991ebe88440b0f875bb1556652927ac9fe61a721b6c666ac6252158ba327ce2868559bafa2c86e7dfef4089782a + languageName: node + linkType: hard + +"@types/prop-types@npm:*": + version: 15.7.5 + resolution: "@types/prop-types@npm:15.7.5" + checksum: 5b43b8b15415e1f298243165f1d44390403bb2bd42e662bca3b5b5633fdd39c938e91b7fce3a9483699db0f7a715d08cef220c121f723a634972fdf596aec980 + languageName: node + linkType: hard + +"@types/react-dom@npm:^18.0.9": + version: 18.0.11 + resolution: "@types/react-dom@npm:18.0.11" + dependencies: + "@types/react": "*" + checksum: 579691e4d5ec09688087568037c35edf8cfb1ab3e07f6c60029280733ee7b5c06d66df6fcc90786702c93ac8cb13bc7ff16c79ddfc75d082938fbaa36e1cdbf4 + languageName: node + linkType: hard + +"@types/react-highlight-words@npm:^0.16.4": + version: 0.16.4 + resolution: "@types/react-highlight-words@npm:0.16.4" + dependencies: + "@types/react": "*" + checksum: 8b7c1b2b63b8f6d58e181613ba5392755b042bf87c74e65caad7bfc4585566944e9aacda6ee3b1cad222aea6667716c8be8643b39b72ae7b4aaadde063a62d25 + languageName: node + linkType: hard + +"@types/react-paginate@npm:^6.2.1": + version: 6.2.3 + resolution: "@types/react-paginate@npm:6.2.3" + dependencies: + "@types/react": "*" + checksum: fd06bf33005cc16a0e70ecb22b82c950432761b1a4dd4f97ff93c8498075fb4deb026e6777c579815213d7fbc7b4e555cc7f9ea1a6262c9b37013d0ebf726c3b + languageName: node + linkType: hard + +"@types/react-test-renderer@npm:^18.0.0": + version: 18.0.0 + resolution: "@types/react-test-renderer@npm:18.0.0" + dependencies: + "@types/react": "*" + checksum: 6afc938a1d7618d88ab8793e251f0bd5981bf3f08c1b600f74df3f8800b92589ea534dc6dcb7c8d683893fcc740bf8d7843a42bf2dae59785cfe88f004bd7b0b + languageName: node + linkType: hard + +"@types/react@npm:^18.0.26": + version: 18.0.28 + resolution: "@types/react@npm:18.0.28" + dependencies: + "@types/prop-types": "*" + "@types/scheduler": "*" + csstype: ^3.0.2 + checksum: e752df961105e5127652460504785897ca6e77259e0da8f233f694f9e8f451cde7fa0709d4456ade0ff600c8ce909cfe29f9b08b9c247fa9b734e126ec53edd7 + languageName: node + linkType: hard + +"@types/responselike@npm:^1.0.0": + version: 1.0.0 + resolution: "@types/responselike@npm:1.0.0" + dependencies: + "@types/node": "*" + checksum: e99fc7cc6265407987b30deda54c1c24bb1478803faf6037557a774b2f034c5b097ffd65847daa87e82a61a250d919f35c3588654b0fdaa816906650f596d1b0 + languageName: node + linkType: hard + +"@types/sanitize-html@npm:^2.3.1": + version: 2.8.1 + resolution: "@types/sanitize-html@npm:2.8.1" + dependencies: + htmlparser2: ^8.0.0 + checksum: 9c07d3a9d925e291472f74b097fb179b32659ea01834f728887811e5fc75cf2b17d844e32e97c0e583eba993af86a3f8250c82c8fa3152abf9ff2a8582972906 + languageName: node + linkType: hard + +"@types/scheduler@npm:*": + version: 0.16.2 + resolution: "@types/scheduler@npm:0.16.2" + checksum: b6b4dcfeae6deba2e06a70941860fb1435730576d3689225a421280b7742318d1548b3d22c1f66ab68e414f346a9542f29240bc955b6332c5b11e561077583bc + languageName: node + linkType: hard + +"@types/semver@npm:^7.1.0, @types/semver@npm:^7.3.12, @types/semver@npm:^7.3.3": + version: 7.5.0 + resolution: "@types/semver@npm:7.5.0" + checksum: 0a64b9b9c7424d9a467658b18dd70d1d781c2d6f033096a6e05762d20ebbad23c1b69b0083b0484722aabf35640b78ccc3de26368bcae1129c87e9df028a22e2 + languageName: node + linkType: hard + +"@types/source-list-map@npm:*": + version: 0.1.2 + resolution: "@types/source-list-map@npm:0.1.2" + checksum: fda8f37537aca9d3ed860d559289ab1dddb6897e642e6f53e909bbd18a7ac3129a8faa2a7d093847c91346cf09c86ef36e350c715406fba1f2271759b449adf6 + languageName: node + linkType: hard + +"@types/stack-utils@npm:^2.0.0": + version: 2.0.1 + resolution: "@types/stack-utils@npm:2.0.1" + checksum: 205fdbe3326b7046d7eaf5e494d8084f2659086a266f3f9cf00bccc549c8e36e407f88168ad4383c8b07099957ad669f75f2532ed4bc70be2b037330f7bae019 + languageName: node + linkType: hard + +"@types/supports-color@npm:^5.3.0": + version: 5.3.0 + resolution: "@types/supports-color@npm:5.3.0" + checksum: abb7d12804402c4f59bf2d9d32800d1fc2b6a1003cb2459fc843e9fa128d24b5a62e6e7cd3d5cdaadcdf9c0af36208a12c9dff4fa9f90de0565f545457a93736 + languageName: node + linkType: hard + +"@types/through@npm:*": + version: 0.0.30 + resolution: "@types/through@npm:0.0.30" + dependencies: + "@types/node": "*" + checksum: 9578470db0b527c26e246a1220ae9bffc6bf47f20f89c54aac467c083ab1f7e16c00d9a7b4bb6cb4e2dfae465027270827e5908a6236063f6214625e50585d78 + languageName: node + linkType: hard + +"@types/tough-cookie@npm:*": + version: 4.0.2 + resolution: "@types/tough-cookie@npm:4.0.2" + checksum: e055556ffdaa39ad85ede0af192c93f93f986f4bd9e9426efdc2948e3e2632db3a4a584d4937dbf6d7620527419bc99e6182d3daf2b08685e710f2eda5291905 + languageName: node + linkType: hard + +"@types/treeify@npm:^1.0.0": + version: 1.0.0 + resolution: "@types/treeify@npm:1.0.0" + checksum: 1b2397030d13beee7f82b878ca80feeddb0d550a6b00d8be30082a370c0ac5985ecf7b9378cf93ea278ff00c3e900b416ae8d9379f2c7e8caecdece1dfc77380 + languageName: node + linkType: hard + +"@types/url-parse@npm:^1.4.3": + version: 1.4.8 + resolution: "@types/url-parse@npm:1.4.8" + checksum: 44a5e96ed4b579c43750f3578bfa9165f97a359c3b2a85ee126e9c16db964f6ea105e152afd3d1adbd15850a8b812043215f3820112177bb4255a60b432dbd85 + languageName: node + linkType: hard + +"@types/webpack-env@npm:^1.18.0": + version: 1.18.0 + resolution: "@types/webpack-env@npm:1.18.0" + checksum: ecf4daa31cb37d474ac0ce058d83a3cadeb9881ca8107ae93c2299eaa9954943aae09b43e143c62ccbe4288a14db00c918c9debd707afe17c3998f873eaabc59 + languageName: node + linkType: hard + +"@types/webpack-sources@npm:^0.1.5": + version: 0.1.9 + resolution: "@types/webpack-sources@npm:0.1.9" + dependencies: + "@types/node": "*" + "@types/source-list-map": "*" + source-map: ^0.6.1 + checksum: bc09c584c7047e8aed29801a3981787dee3898e9e7a99891a362df114fcac3879eea5a00932314866a01b25220391839be09fe1487b16d4970ff4a7afd5b9725 + languageName: node + linkType: hard + +"@types/ws@npm:^8.5.3": + version: 8.5.4 + resolution: "@types/ws@npm:8.5.4" + dependencies: + "@types/node": "*" + checksum: fefbad20d211929bb996285c4e6f699b12192548afedbe4930ab4384f8a94577c9cd421acaad163cacd36b88649509970a05a0b8f20615b30c501ed5269038d1 + languageName: node + linkType: hard + +"@types/yargs-parser@npm:*": + version: 21.0.0 + resolution: "@types/yargs-parser@npm:21.0.0" + checksum: b2f4c8d12ac18a567440379909127cf2cec393daffb73f246d0a25df36ea983b93b7e9e824251f959e9f928cbc7c1aab6728d0a0ff15d6145f66cec2be67d9a2 + languageName: node + linkType: hard + +"@types/yargs@npm:^17.0.8": + version: 17.0.22 + resolution: "@types/yargs@npm:17.0.22" + dependencies: + "@types/yargs-parser": "*" + checksum: 0773523fda71bafdc52f13f5970039e535a353665a60ba9261149a5c9c2b908242e6e77fbb7a8c06931ec78ce889d64d09673c68ba23eb5f5742d5385d0d1982 + languageName: node + linkType: hard + +"@typescript-eslint/eslint-plugin@npm:~5.55.0": + version: 5.55.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.55.0" + dependencies: + "@eslint-community/regexpp": ^4.4.0 + "@typescript-eslint/scope-manager": 5.55.0 + "@typescript-eslint/type-utils": 5.55.0 + "@typescript-eslint/utils": 5.55.0 + debug: ^4.3.4 + grapheme-splitter: ^1.0.4 + ignore: ^5.2.0 + natural-compare-lite: ^1.4.0 + semver: ^7.3.7 + tsutils: ^3.21.0 + peerDependencies: + "@typescript-eslint/parser": ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: e3239ec6016eeb73b8b4d8310581978e28b8d3378140a8eb70bd8e33ffd332266020c19d493e0ccae4edfd4abd6097608718c50308fe6288f4ffeb8e4784efd9 + languageName: node + linkType: hard + +"@typescript-eslint/parser@npm:~5.55.0": + version: 5.55.0 + resolution: "@typescript-eslint/parser@npm:5.55.0" + dependencies: + "@typescript-eslint/scope-manager": 5.55.0 + "@typescript-eslint/types": 5.55.0 + "@typescript-eslint/typescript-estree": 5.55.0 + debug: ^4.3.4 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 48a20dc7e67960b5168b77bfb9d11d053a21d57bb83cf7b59f750191cbca5eea3b4636a8e6e75cc0aca5a84cdef91fed5440934fc2935f8c6fa71630a253a50c + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:5.55.0": + version: 5.55.0 + resolution: "@typescript-eslint/scope-manager@npm:5.55.0" + dependencies: + "@typescript-eslint/types": 5.55.0 + "@typescript-eslint/visitor-keys": 5.55.0 + checksum: f253db88f69a29e4abe2f567d0a611cc3e7fb1a911a2cc54a2f6baf16e3de4d1883b3f8e45ee61b3db9fa5543dda0fd7b608de9d28ba6173ab49bfd17ff90cad + languageName: node + linkType: hard + +"@typescript-eslint/type-utils@npm:5.55.0": + version: 5.55.0 + resolution: "@typescript-eslint/type-utils@npm:5.55.0" + dependencies: + "@typescript-eslint/typescript-estree": 5.55.0 + "@typescript-eslint/utils": 5.55.0 + debug: ^4.3.4 + tsutils: ^3.21.0 + peerDependencies: + eslint: "*" + peerDependenciesMeta: + typescript: + optional: true + checksum: 5c60d441355b51f96b596324068c10605c74abb46748c0bbc6d8f7f2ea40acb6b4bda3b537105fa189172324c56d18bd88e7102e67f99f8c03bc05c6d0e2023d + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:5.55.0": + version: 5.55.0 + resolution: "@typescript-eslint/types@npm:5.55.0" + checksum: 7d851f09a2106514d3a9c7164d34758f30abfe554e3c7a02be75cdc7e16644e23ca32840a8f39a0321bc509927fb4d98ce91b22b21e8544ac56cef33b815a864 + languageName: node + linkType: hard + +"@typescript-eslint/typescript-estree@npm:5.55.0": + version: 5.55.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.55.0" + dependencies: + "@typescript-eslint/types": 5.55.0 + "@typescript-eslint/visitor-keys": 5.55.0 + debug: ^4.3.4 + globby: ^11.1.0 + is-glob: ^4.0.3 + semver: ^7.3.7 + tsutils: ^3.21.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: d24a11aee3d01067018d99804f420aecb8af88e43bf170d5d14f6480bd378c0a81ce49a37f5d6c36e5f0f319e3fa8b099720f295f2767338be1a4f7e9a5323e1 + languageName: node + linkType: hard + +"@typescript-eslint/utils@npm:5.55.0, @typescript-eslint/utils@npm:^5.10.0": + version: 5.55.0 + resolution: "@typescript-eslint/utils@npm:5.55.0" + dependencies: + "@eslint-community/eslint-utils": ^4.2.0 + "@types/json-schema": ^7.0.9 + "@types/semver": ^7.3.12 + "@typescript-eslint/scope-manager": 5.55.0 + "@typescript-eslint/types": 5.55.0 + "@typescript-eslint/typescript-estree": 5.55.0 + eslint-scope: ^5.1.1 + semver: ^7.3.7 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 368cfc3fb9d6af6901e739e2e41c3f7f1c1244576607445f4f59d95eccb237f73e1a75e7f0816ec9a32a0f1ec6bb4a3602a99e17e70fe184e62f7c69dcbe4b8d + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:5.55.0": + version: 5.55.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.55.0" + dependencies: + "@typescript-eslint/types": 5.55.0 + eslint-visitor-keys: ^3.3.0 + checksum: 0b24c72dff99dd2cf41c19d20067f8ab20a38aa2e82c79c5530bec7cf651031e95c80702fc21c813c9b94e5f3d4cd210f13967b2966ef38abe548cb5f05848a3 + languageName: node + linkType: hard + +"@verdaccio/commons-api@npm:10.2.0": + version: 10.2.0 + resolution: "@verdaccio/commons-api@npm:10.2.0" + dependencies: + http-errors: 2.0.0 + http-status-codes: 2.2.0 + checksum: b3c946f7e15140b4e15274fa9988a8759681e9ad4316ec882096551588f554c093fb1ffbbb88ed05db162e1b0e40e9859759e1339f0ae4a074706afb7e732be2 + languageName: node + linkType: hard + +"@verdaccio/config@npm:6.0.0-6-next.71": + version: 6.0.0-6-next.71 + resolution: "@verdaccio/config@npm:6.0.0-6-next.71" + dependencies: + "@verdaccio/core": 6.0.0-6-next.71 + "@verdaccio/utils": 6.0.0-6-next.39 + debug: 4.3.4 + js-yaml: 4.1.0 + lodash: 4.17.21 + minimatch: 3.1.2 + yup: 0.32.11 + checksum: a62bc7f6f6799d8f9b7d056303f7c1867adebf250f25662a38bc2208efe939fb9d3edbca7a694276d51f7c9402d7adcdcc1f1f5bfeef6d60b8b41c7f5d7d0ceb + languageName: node + linkType: hard + +"@verdaccio/core@npm:6.0.0-6-next.71": + version: 6.0.0-6-next.71 + resolution: "@verdaccio/core@npm:6.0.0-6-next.71" + dependencies: + ajv: 8.12.0 + core-js: 3.30.2 + http-errors: 2.0.0 + http-status-codes: 2.2.0 + process-warning: 1.0.0 + semver: 7.5.0 + checksum: d5c61d9e86bec1fbb58b2df5f8b83d0e60871173b7a160957a67805dbaec95656142853e6e99812870208b2eec754bc5d2f0b6fd3e3e9878678afcf6648d65fa + languageName: node + linkType: hard + +"@verdaccio/file-locking@npm:10.3.1": + version: 10.3.1 + resolution: "@verdaccio/file-locking@npm:10.3.1" + dependencies: + lockfile: 1.0.4 + checksum: 114948ed4ce9c0f98008eaf32355f902c4dfc91c0ce2e539a3d0c9397781e9ef8d1a2f6ce900d39dac0e054a9d7e616edbc472eedf758096fcd3cc8294d6add5 + languageName: node + linkType: hard + +"@verdaccio/file-locking@npm:11.0.0-6-next.7": + version: 11.0.0-6-next.7 + resolution: "@verdaccio/file-locking@npm:11.0.0-6-next.7" + dependencies: + lockfile: 1.0.4 + checksum: 86cf13ab75c3e11958201433aa2b98bba70f90cb855e5d84063affd491ce31f12093a8874a09a45f1ed8ee320457d55e96161d8957e11dd8e8ec7dd4c1b06443 + languageName: node + linkType: hard + +"@verdaccio/local-storage@npm:10.3.3": + version: 10.3.3 + resolution: "@verdaccio/local-storage@npm:10.3.3" + dependencies: + "@verdaccio/commons-api": 10.2.0 + "@verdaccio/file-locking": 10.3.1 + "@verdaccio/streams": 10.2.1 + async: 3.2.4 + debug: 4.3.4 + lodash: 4.17.21 + lowdb: 1.0.0 + mkdirp: 1.0.4 + checksum: 70f47ea94fd0d6f3a5ac82fa0a8b28a41fb69f076f993bbf9ff775cca11966a6e92b4b57741348bdbfc3f241d851c052336d1673ca7e7b29e1999b88afe4fde2 + languageName: node + linkType: hard + +"@verdaccio/logger-7@npm:6.0.0-6-next.16": + version: 6.0.0-6-next.16 + resolution: "@verdaccio/logger-7@npm:6.0.0-6-next.16" + dependencies: + "@verdaccio/logger-commons": 6.0.0-6-next.39 + pino: 7.11.0 + checksum: 0e30e693c509257e9f28475f26c0ea682cbb0ca34bd4651d072b21e61b491c72ae453e9d96fc930412aa25d7d8599bb9bf206c3d6c979a77eff836dfb2522ba4 + languageName: node + linkType: hard + +"@verdaccio/logger-commons@npm:6.0.0-6-next.39": + version: 6.0.0-6-next.39 + resolution: "@verdaccio/logger-commons@npm:6.0.0-6-next.39" + dependencies: + "@verdaccio/core": 6.0.0-6-next.71 + "@verdaccio/logger-prettify": 6.0.0-6-next.10 + colorette: 2.0.20 + debug: 4.3.4 + checksum: 81c8901c281210402612dbde1a46e0771fbd53ba82bf59a8096547dcbbbf0b27c757c72b37746fb8ffee0f858e7a28519917f2fac4b452dab90a88d5fe377a4f + languageName: node + linkType: hard + +"@verdaccio/logger-prettify@npm:6.0.0-6-next.10": + version: 6.0.0-6-next.10 + resolution: "@verdaccio/logger-prettify@npm:6.0.0-6-next.10" + dependencies: + colorette: 2.0.20 + dayjs: 1.11.7 + lodash: 4.17.21 + pino-abstract-transport: 1.0.0 + sonic-boom: 3.3.0 + checksum: a596da36e55fb7cf4bbe7a12865756d02dd9d573a05673a847c97d18dc84bcd534656e63cade4f478e0380c1d2f41ade08ffe47dcb3b7f64ea913bca5331e071 + languageName: node + linkType: hard + +"@verdaccio/middleware@npm:6.0.0-6-next.50": + version: 6.0.0-6-next.50 + resolution: "@verdaccio/middleware@npm:6.0.0-6-next.50" + dependencies: + "@verdaccio/config": 6.0.0-6-next.71 + "@verdaccio/core": 6.0.0-6-next.71 + "@verdaccio/url": 11.0.0-6-next.37 + "@verdaccio/utils": 6.0.0-6-next.39 + debug: 4.3.4 + express: 4.18.2 + express-rate-limit: 5.5.1 + lodash: 4.17.21 + lru-cache: 7.18.3 + mime: 2.6.0 + checksum: 029d505d7f787463ac41b143b43724158ec91270e913fb3458a551e1303cfd87980ed9581a230ccda04082fd3c02233e464e00136b4b1cd1726fcde02ef81b09 + languageName: node + linkType: hard + +"@verdaccio/search@npm:6.0.0-6-next.2": + version: 6.0.0-6-next.2 + resolution: "@verdaccio/search@npm:6.0.0-6-next.2" + checksum: 33f85e5e15f77826b4d8cded78b899234fa63e660c7d5530ae5230a507561e1ab31ea96b304735e05c990fa15a653ba7b89cdc7e7e6e7e221a376a48a4670aa0 + languageName: node + linkType: hard + +"@verdaccio/signature@npm:6.0.0-6-next.2": + version: 6.0.0-6-next.2 + resolution: "@verdaccio/signature@npm:6.0.0-6-next.2" + dependencies: + debug: 4.3.4 + jsonwebtoken: 9.0.0 + lodash: 4.17.21 + checksum: 6e5331ee231be43cf521596f9ee6d1c39d73f249822e5cbe0e83ac91b3a4849adf53c6e9b4566a674b4134ecd2706e6734a1344cc8fa8dbe82232642ee07f631 + languageName: node + linkType: hard + +"@verdaccio/streams@npm:10.2.1": + version: 10.2.1 + resolution: "@verdaccio/streams@npm:10.2.1" + checksum: eadc671c2b40ea06da8c56bd2e5b394edbfdc2895f4e622491d4edd4312468d8172534ddaf364e107d118c7c7585f2f9114336ee93a16f0ec747c4ea15c6737b + languageName: node + linkType: hard + +"@verdaccio/tarball@npm:11.0.0-6-next.40": + version: 11.0.0-6-next.40 + resolution: "@verdaccio/tarball@npm:11.0.0-6-next.40" + dependencies: + "@verdaccio/core": 6.0.0-6-next.71 + "@verdaccio/url": 11.0.0-6-next.37 + "@verdaccio/utils": 6.0.0-6-next.39 + debug: 4.3.4 + lodash: 4.17.21 + checksum: cf751ef3a983dd0438aa0e1759c1e4a042b5666e54873c51438fabf929b892bb4710f6946c5b92a728b97c7a97535d5a873edfeaf9a92e59e6daa1f16dd26cbb + languageName: node + linkType: hard + +"@verdaccio/ui-theme@npm:6.0.0-6-next.71": + version: 6.0.0-6-next.71 + resolution: "@verdaccio/ui-theme@npm:6.0.0-6-next.71" + checksum: 5977d52353b4fb9534d0d7420ba71b02f15d0dc9ac77bdbc90f49aa1c9d85601a1b4adabe490ec8d0baf9d72da22682618719e250c53925b3a84f3d77456e4a2 + languageName: node + linkType: hard + +"@verdaccio/url@npm:11.0.0-6-next.37": + version: 11.0.0-6-next.37 + resolution: "@verdaccio/url@npm:11.0.0-6-next.37" + dependencies: + "@verdaccio/core": 6.0.0-6-next.71 + debug: 4.3.4 + lodash: 4.17.21 + validator: 13.9.0 + checksum: 7b4e8d25d195e32c05173a9299339ef0a86bcfcd0479eee6827cec9ec3c09dc1659df7953dc1aa8fad443293ead6a215cb1e037b503351852caa1a2d47c495fd + languageName: node + linkType: hard + +"@verdaccio/utils@npm:6.0.0-6-next.39": + version: 6.0.0-6-next.39 + resolution: "@verdaccio/utils@npm:6.0.0-6-next.39" + dependencies: + "@verdaccio/core": 6.0.0-6-next.71 + lodash: 4.17.21 + minimatch: 3.1.2 + semver: 7.5.0 + checksum: afca006f9c8ba66c1d0a4b2eb9b92a63b10841cdd8f1a1a8942a2ec6d0708392e407cbb670f6415562aa5145ce85d5004a8e4fb8cdba703a9f5e82076790154c + languageName: node + linkType: hard + +"@vscode/debugprotocol@npm:^1.51.0": + version: 1.59.0 + resolution: "@vscode/debugprotocol@npm:1.59.0" + checksum: 7a7de9e51f791b217da2e6f0d7a08e4732f933e973eaa24b9e7078958c8d6828401f2591334968bb067d42e4dd09ea4ad209f2e32caed8c31b4329320976af5e + languageName: node + linkType: hard + +"@webassemblyjs/ast@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/ast@npm:1.11.1" + dependencies: + "@webassemblyjs/helper-numbers": 1.11.1 + "@webassemblyjs/helper-wasm-bytecode": 1.11.1 + checksum: 1eee1534adebeece635362f8e834ae03e389281972611408d64be7895fc49f48f98fddbbb5339bf8a72cb101bcb066e8bca3ca1bf1ef47dadf89def0395a8d87 + languageName: node + linkType: hard + +"@webassemblyjs/floating-point-hex-parser@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.11.1" + checksum: b8efc6fa08e4787b7f8e682182d84dfdf8da9d9c77cae5d293818bc4a55c1f419a87fa265ab85252b3e6c1fd323d799efea68d825d341a7c365c64bc14750e97 + languageName: node + linkType: hard + +"@webassemblyjs/helper-api-error@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/helper-api-error@npm:1.11.1" + checksum: 0792813f0ed4a0e5ee0750e8b5d0c631f08e927f4bdfdd9fe9105dc410c786850b8c61bff7f9f515fdfb149903bec3c976a1310573a4c6866a94d49bc7271959 + languageName: node + linkType: hard + +"@webassemblyjs/helper-buffer@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/helper-buffer@npm:1.11.1" + checksum: a337ee44b45590c3a30db5a8b7b68a717526cf967ada9f10253995294dbd70a58b2da2165222e0b9830cd4fc6e4c833bf441a721128d1fe2e9a7ab26b36003ce + languageName: node + linkType: hard + +"@webassemblyjs/helper-numbers@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/helper-numbers@npm:1.11.1" + dependencies: + "@webassemblyjs/floating-point-hex-parser": 1.11.1 + "@webassemblyjs/helper-api-error": 1.11.1 + "@xtuc/long": 4.2.2 + checksum: 44d2905dac2f14d1e9b5765cf1063a0fa3d57295c6d8930f6c59a36462afecc6e763e8a110b97b342a0f13376166c5d41aa928e6ced92e2f06b071fd0db59d3a + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-bytecode@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.11.1" + checksum: eac400113127832c88f5826bcc3ad1c0db9b3dbd4c51a723cfdb16af6bfcbceb608170fdaac0ab7731a7e18b291be7af68a47fcdb41cfe0260c10857e7413d97 + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-section@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/helper-wasm-section@npm:1.11.1" + dependencies: + "@webassemblyjs/ast": 1.11.1 + "@webassemblyjs/helper-buffer": 1.11.1 + "@webassemblyjs/helper-wasm-bytecode": 1.11.1 + "@webassemblyjs/wasm-gen": 1.11.1 + checksum: 617696cfe8ecaf0532763162aaf748eb69096fb27950219bb87686c6b2e66e11cd0614d95d319d0ab1904bc14ebe4e29068b12c3e7c5e020281379741fe4bedf + languageName: node + linkType: hard + +"@webassemblyjs/ieee754@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/ieee754@npm:1.11.1" + dependencies: + "@xtuc/ieee754": ^1.2.0 + checksum: 23a0ac02a50f244471631802798a816524df17e56b1ef929f0c73e3cde70eaf105a24130105c60aff9d64a24ce3b640dad443d6f86e5967f922943a7115022ec + languageName: node + linkType: hard + +"@webassemblyjs/leb128@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/leb128@npm:1.11.1" + dependencies: + "@xtuc/long": 4.2.2 + checksum: 33ccc4ade2f24de07bf31690844d0b1ad224304ee2062b0e464a610b0209c79e0b3009ac190efe0e6bd568b0d1578d7c3047fc1f9d0197c92fc061f56224ff4a + languageName: node + linkType: hard + +"@webassemblyjs/utf8@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/utf8@npm:1.11.1" + checksum: 972c5cfc769d7af79313a6bfb96517253a270a4bf0c33ba486aa43cac43917184fb35e51dfc9e6b5601548cd5931479a42e42c89a13bb591ffabebf30c8a6a0b + languageName: node + linkType: hard + +"@webassemblyjs/wasm-edit@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/wasm-edit@npm:1.11.1" + dependencies: + "@webassemblyjs/ast": 1.11.1 + "@webassemblyjs/helper-buffer": 1.11.1 + "@webassemblyjs/helper-wasm-bytecode": 1.11.1 + "@webassemblyjs/helper-wasm-section": 1.11.1 + "@webassemblyjs/wasm-gen": 1.11.1 + "@webassemblyjs/wasm-opt": 1.11.1 + "@webassemblyjs/wasm-parser": 1.11.1 + "@webassemblyjs/wast-printer": 1.11.1 + checksum: 6d7d9efaec1227e7ef7585a5d7ff0be5f329f7c1c6b6c0e906b18ed2e9a28792a5635e450aca2d136770d0207225f204eff70a4b8fd879d3ac79e1dcc26dbeb9 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-gen@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/wasm-gen@npm:1.11.1" + dependencies: + "@webassemblyjs/ast": 1.11.1 + "@webassemblyjs/helper-wasm-bytecode": 1.11.1 + "@webassemblyjs/ieee754": 1.11.1 + "@webassemblyjs/leb128": 1.11.1 + "@webassemblyjs/utf8": 1.11.1 + checksum: 1f6921e640293bf99fb16b21e09acb59b340a79f986c8f979853a0ae9f0b58557534b81e02ea2b4ef11e929d946708533fd0693c7f3712924128fdafd6465f5b + languageName: node + linkType: hard + +"@webassemblyjs/wasm-opt@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/wasm-opt@npm:1.11.1" + dependencies: + "@webassemblyjs/ast": 1.11.1 + "@webassemblyjs/helper-buffer": 1.11.1 + "@webassemblyjs/wasm-gen": 1.11.1 + "@webassemblyjs/wasm-parser": 1.11.1 + checksum: 21586883a20009e2b20feb67bdc451bbc6942252e038aae4c3a08e6f67b6bae0f5f88f20bfc7bd0452db5000bacaf5ab42b98cf9aa034a6c70e9fc616142e1db + languageName: node + linkType: hard + +"@webassemblyjs/wasm-parser@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/wasm-parser@npm:1.11.1" + dependencies: + "@webassemblyjs/ast": 1.11.1 + "@webassemblyjs/helper-api-error": 1.11.1 + "@webassemblyjs/helper-wasm-bytecode": 1.11.1 + "@webassemblyjs/ieee754": 1.11.1 + "@webassemblyjs/leb128": 1.11.1 + "@webassemblyjs/utf8": 1.11.1 + checksum: 1521644065c360e7b27fad9f4bb2df1802d134dd62937fa1f601a1975cde56bc31a57b6e26408b9ee0228626ff3ba1131ae6f74ffb7d718415b6528c5a6dbfc2 + languageName: node + linkType: hard + +"@webassemblyjs/wast-printer@npm:1.11.1": + version: 1.11.1 + resolution: "@webassemblyjs/wast-printer@npm:1.11.1" + dependencies: + "@webassemblyjs/ast": 1.11.1 + "@xtuc/long": 4.2.2 + checksum: f15ae4c2441b979a3b4fce78f3d83472fb22350c6dc3fd34bfe7c3da108e0b2360718734d961bba20e7716cb8578e964b870da55b035e209e50ec9db0378a3f7 + languageName: node + linkType: hard + +"@webpack-cli/configtest@npm:^2.0.1": + version: 2.0.1 + resolution: "@webpack-cli/configtest@npm:2.0.1" + peerDependencies: + webpack: 5.x.x + webpack-cli: 5.x.x + checksum: 15d0ca835f2e16ec99e9f295f07b676435b9e706d7700df0ad088692fea065e34772fc44b96a4f6a86178b9ca8cf1ff941fbce15269587cf0925d70b18928cea + languageName: node + linkType: hard + +"@webpack-cli/info@npm:^2.0.1": + version: 2.0.1 + resolution: "@webpack-cli/info@npm:2.0.1" + peerDependencies: + webpack: 5.x.x + webpack-cli: 5.x.x + checksum: b8fba49fee10d297c2affb0b064c9a81e9038d75517c6728fb85f9fb254cae634e5d33e696dac5171e6944ae329d85fddac72f781c7d833f7e9dfe43151ce60d + languageName: node + linkType: hard + +"@webpack-cli/serve@npm:^2.0.1": + version: 2.0.1 + resolution: "@webpack-cli/serve@npm:2.0.1" + peerDependencies: + webpack: 5.x.x + webpack-cli: 5.x.x + peerDependenciesMeta: + webpack-dev-server: + optional: true + checksum: 75c55f8398dd60e4821f81bec6e96287cebb3ab1837ef016779bc2f0c76a1d29c45b99e53daa99ba1fa156b5e2b61c19abf58098de20c2b58391b1f496ecc145 + languageName: node + linkType: hard + +"@xtuc/ieee754@npm:^1.2.0": + version: 1.2.0 + resolution: "@xtuc/ieee754@npm:1.2.0" + checksum: ac56d4ca6e17790f1b1677f978c0c6808b1900a5b138885d3da21732f62e30e8f0d9120fcf8f6edfff5100ca902b46f8dd7c1e3f903728634523981e80e2885a + languageName: node + linkType: hard + +"@xtuc/long@npm:4.2.2": + version: 4.2.2 + resolution: "@xtuc/long@npm:4.2.2" + checksum: 8ed0d477ce3bc9c6fe2bf6a6a2cc316bb9c4127c5a7827bae947fa8ec34c7092395c5a283cc300c05b5fa01cbbfa1f938f410a7bf75db7c7846fea41949989ec + languageName: node + linkType: hard + +"@yarnpkg/core@npm:^3.0.0": + version: 3.5.2 + resolution: "@yarnpkg/core@npm:3.5.2" + dependencies: + "@arcanis/slice-ansi": ^1.1.1 + "@types/semver": ^7.1.0 + "@types/treeify": ^1.0.0 + "@yarnpkg/fslib": ^2.10.3 + "@yarnpkg/json-proxy": ^2.1.1 + "@yarnpkg/libzip": ^2.3.0 + "@yarnpkg/parsers": ^2.5.1 + "@yarnpkg/pnp": ^3.3.3 + "@yarnpkg/shell": ^3.2.5 + camelcase: ^5.3.1 + chalk: ^3.0.0 + ci-info: ^3.2.0 + clipanion: 3.2.0-rc.4 + cross-spawn: 7.0.3 + diff: ^5.1.0 + globby: ^11.0.1 + got: ^11.7.0 + json-file-plus: ^3.3.1 + lodash: ^4.17.15 + micromatch: ^4.0.2 + mkdirp: ^0.5.1 + p-limit: ^2.2.0 + pluralize: ^7.0.0 + pretty-bytes: ^5.1.0 + semver: ^7.1.2 + stream-to-promise: ^2.2.0 + strip-ansi: ^6.0.0 + tar: ^6.0.5 + tinylogic: ^1.0.3 + treeify: ^1.1.0 + tslib: ^1.13.0 + tunnel: ^0.0.6 + checksum: 7635ea96c79195afc2146a1b8c5adfcb765a83bce2721bc0c88799a01e0e0b73243631f47b57df14667d7349aa0cf0a6b28b6ecfc9814ef329c7dd1f4c7f3826 + languageName: node + linkType: hard + +"@yarnpkg/fslib@npm:^2.10.3, @yarnpkg/fslib@npm:^2.5.0, @yarnpkg/fslib@npm:^2.9.0": + version: 2.10.3 + resolution: "@yarnpkg/fslib@npm:2.10.3" + dependencies: + "@yarnpkg/libzip": ^2.3.0 + tslib: ^1.13.0 + checksum: 0ca693f61d47bcf165411a121ed9123f512b1b5bfa5e1c6c8f280b4ffdbea9bf2a6db418f99ecfc9624587fdc695b2b64eb0fe7b4028e44095914b25ca99655e + languageName: node + linkType: hard + +"@yarnpkg/json-proxy@npm:^2.1.1": + version: 2.1.1 + resolution: "@yarnpkg/json-proxy@npm:2.1.1" + dependencies: + "@yarnpkg/fslib": ^2.5.0 + tslib: ^1.13.0 + checksum: 2c306b6ee158d48b15f4b09e7fb431b1096d4687c77cc49a9b37dbda04c05f13ef19175c795feefe1068668d0519a1caff7b3b7f6441a1ac6a5702ef0d60c250 + languageName: node + linkType: hard + +"@yarnpkg/libzip@npm:^2.3.0": + version: 2.3.0 + resolution: "@yarnpkg/libzip@npm:2.3.0" + dependencies: + "@types/emscripten": ^1.39.6 + tslib: ^1.13.0 + checksum: 533a4883f69bb013f955d80dc19719881697e6849ea5f0cbe6d87ef1d582b05cbae8a453802f92ad0c852f976296cac3ff7834be79a7e415b65cdf213e448110 + languageName: node + linkType: hard + +"@yarnpkg/lockfile@npm:^1.1.0": + version: 1.1.0 + resolution: "@yarnpkg/lockfile@npm:1.1.0" + checksum: 05b881b4866a3546861fee756e6d3812776ea47fa6eb7098f983d6d0eefa02e12b66c3fff931574120f196286a7ad4879ce02743c8bb2be36c6a576c7852083a + languageName: node + linkType: hard + +"@yarnpkg/parsers@npm:3.0.0-rc.46": + version: 3.0.0-rc.46 + resolution: "@yarnpkg/parsers@npm:3.0.0-rc.46" + dependencies: + js-yaml: ^3.10.0 + tslib: ^2.4.0 + checksum: 35dfd1b1ac7ed9babf231721eb90b58156e840e575f6792a8e5ab559beaed6e2d60833b857310e67d6282c9406357648df2f510e670ec37ef4bd41657f329a51 + languageName: node + linkType: hard + +"@yarnpkg/parsers@npm:^2.0.0, @yarnpkg/parsers@npm:^2.5.1": + version: 2.5.1 + resolution: "@yarnpkg/parsers@npm:2.5.1" + dependencies: + js-yaml: ^3.10.0 + tslib: ^1.13.0 + checksum: 42f98b8bd635add304ce392c6f600b46e40c2c4429d7b6c38b70f50b5fd6a854dd2369e0987b70546a3c8f690d280f040a885b35acfde891f5e173fc3f974277 + languageName: node + linkType: hard + +"@yarnpkg/pnp@npm:^3.3.3": + version: 3.3.4 + resolution: "@yarnpkg/pnp@npm:3.3.4" + dependencies: + "@types/node": ^13.7.0 + "@yarnpkg/fslib": ^2.10.3 + checksum: ab6a5425997d18dc0d3897f29218d484eb417cf964640a37380e16ac7862390b63bb24227164568bec59da7d70dc1028ee0a1cc7356eb8c605c94e7cbffe67eb + languageName: node + linkType: hard + +"@yarnpkg/shell@npm:^3.2.5": + version: 3.2.5 + resolution: "@yarnpkg/shell@npm:3.2.5" + dependencies: + "@yarnpkg/fslib": ^2.9.0 + "@yarnpkg/parsers": ^2.5.1 + chalk: ^3.0.0 + clipanion: 3.2.0-rc.4 + cross-spawn: 7.0.3 + fast-glob: ^3.2.2 + micromatch: ^4.0.2 + stream-buffers: ^3.0.2 + tslib: ^1.13.0 + bin: + shell: ./lib/cli.js + checksum: 89fe80fec6ccd5a1a713ea11285bce17fe1f3cc42507b4e63565818c4afb41e588d368cf7c198fe2b3eeb900cae87233c2d52c27da288a57f82f85a07cf9b221 + languageName: node + linkType: hard + +"@zkochan/js-yaml@npm:0.0.6": + version: 0.0.6 + resolution: "@zkochan/js-yaml@npm:0.0.6" + dependencies: + argparse: ^2.0.1 + bin: + js-yaml: bin/js-yaml.js + checksum: 51b81597a1d1d79c778b8fae48317eaad78d75223d0b7477ad2b35f47cf63b19504da430bb7a03b326e668b282874242cc123e323e57293be038684cb5e755f8 + languageName: node + linkType: hard + +"JSONStream@npm:1.3.5, JSONStream@npm:^1.3.5": + version: 1.3.5 + resolution: "JSONStream@npm:1.3.5" + dependencies: + jsonparse: ^1.2.0 + through: ">=2.2.7 <3" + bin: + JSONStream: ./bin.js + checksum: 2605fa124260c61bad38bb65eba30d2f72216a78e94d0ab19b11b4e0327d572b8d530c0c9cc3b0764f727ad26d39e00bf7ebad57781ca6368394d73169c59e46 + languageName: node + linkType: hard + +"abab@npm:^2.0.3, abab@npm:^2.0.6": + version: 2.0.6 + resolution: "abab@npm:2.0.6" + checksum: 6ffc1af4ff315066c62600123990d87551ceb0aafa01e6539da77b0f5987ac7019466780bf480f1787576d4385e3690c81ccc37cfda12819bf510b8ab47e5a3e + languageName: node + linkType: hard + +"abbrev@npm:1, abbrev@npm:^1.0.0": + version: 1.1.1 + resolution: "abbrev@npm:1.1.1" + checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 + languageName: node + linkType: hard + +"abort-controller@npm:^3.0.0": + version: 3.0.0 + resolution: "abort-controller@npm:3.0.0" + dependencies: + event-target-shim: ^5.0.0 + checksum: 170bdba9b47b7e65906a28c8ce4f38a7a369d78e2271706f020849c1bfe0ee2067d4261df8bbb66eb84f79208fd5b710df759d64191db58cfba7ce8ef9c54b75 + languageName: node + linkType: hard + +"accepts@npm:~1.3.5, accepts@npm:~1.3.8": + version: 1.3.8 + resolution: "accepts@npm:1.3.8" + dependencies: + mime-types: ~2.1.34 + negotiator: 0.6.3 + checksum: 50c43d32e7b50285ebe84b613ee4a3aa426715a7d131b65b786e2ead0fd76b6b60091b9916d3478a75f11f162628a2139991b6c03ab3f1d9ab7c86075dc8eab4 + languageName: node + linkType: hard + +"acorn-globals@npm:^7.0.0": + version: 7.0.1 + resolution: "acorn-globals@npm:7.0.1" + dependencies: + acorn: ^8.1.0 + acorn-walk: ^8.0.2 + checksum: 2a2998a547af6d0db5f0cdb90acaa7c3cbca6709010e02121fb8b8617c0fbd8bab0b869579903fde358ac78454356a14fadcc1a672ecb97b04b1c2ccba955ce8 + languageName: node + linkType: hard + +"acorn-import-assertions@npm:^1.7.6": + version: 1.8.0 + resolution: "acorn-import-assertions@npm:1.8.0" + peerDependencies: + acorn: ^8 + checksum: 5c4cf7c850102ba7ae0eeae0deb40fb3158c8ca5ff15c0bca43b5c47e307a1de3d8ef761788f881343680ea374631ae9e9615ba8876fee5268dbe068c98bcba6 + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.3.2": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 + languageName: node + linkType: hard + +"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.0.2": + version: 8.2.0 + resolution: "acorn-walk@npm:8.2.0" + checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 + languageName: node + linkType: hard + +"acorn@npm:^8.0.4, acorn@npm:^8.1.0, acorn@npm:^8.5.0, acorn@npm:^8.7.1, acorn@npm:^8.8.0, acorn@npm:^8.8.1": + version: 8.8.2 + resolution: "acorn@npm:8.8.2" + bin: + acorn: bin/acorn + checksum: f790b99a1bf63ef160c967e23c46feea7787e531292bb827126334612c234ed489a0dc2c7ba33156416f0ffa8d25bf2b0fdb7f35c2ba60eb3e960572bece4001 + languageName: node + linkType: hard + +"add-stream@npm:^1.0.0": + version: 1.0.0 + resolution: "add-stream@npm:1.0.0" + checksum: 3e9e8b0b8f0170406d7c3a9a39bfbdf419ccccb0fd2a396338c0fda0a339af73bf738ad414fc520741de74517acf0dd92b4a36fd3298a47fd5371eee8f2c5a06 + languageName: node + linkType: hard + +"agent-base@npm:6, agent-base@npm:^6.0.2": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: 4 + checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d + languageName: node + linkType: hard + +"agentkeepalive@npm:^4.2.1": + version: 4.3.0 + resolution: "agentkeepalive@npm:4.3.0" + dependencies: + debug: ^4.1.0 + depd: ^2.0.0 + humanize-ms: ^1.2.1 + checksum: 982453aa44c11a06826c836025e5162c846e1200adb56f2d075400da7d32d87021b3b0a58768d949d824811f5654223d5a8a3dad120921a2439625eb847c6260 + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: ^2.0.0 + indent-string: ^4.0.0 + checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + languageName: node + linkType: hard + +"ajv-formats@npm:^2.1.1": + version: 2.1.1 + resolution: "ajv-formats@npm:2.1.1" + dependencies: + ajv: ^8.0.0 + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 4a287d937f1ebaad4683249a4c40c0fa3beed30d9ddc0adba04859026a622da0d317851316ea64b3680dc60f5c3c708105ddd5d5db8fe595d9d0207fd19f90b7 + languageName: node + linkType: hard + +"ajv-keywords@npm:^3.5.2": + version: 3.5.2 + resolution: "ajv-keywords@npm:3.5.2" + peerDependencies: + ajv: ^6.9.1 + checksum: 7dc5e5931677a680589050f79dcbe1fefbb8fea38a955af03724229139175b433c63c68f7ae5f86cf8f65d55eb7c25f75a046723e2e58296707617ca690feae9 + languageName: node + linkType: hard + +"ajv-keywords@npm:^5.0.0": + version: 5.1.0 + resolution: "ajv-keywords@npm:5.1.0" + dependencies: + fast-deep-equal: ^3.1.3 + peerDependencies: + ajv: ^8.8.2 + checksum: c35193940b853119242c6757787f09ecf89a2c19bcd36d03ed1a615e710d19d450cb448bfda407b939aba54b002368c8bff30529cc50a0536a8e10bcce300421 + languageName: node + linkType: hard + +"ajv@npm:8.12.0, ajv@npm:^8.0.0, ajv@npm:^8.0.1, ajv@npm:^8.12.0, ajv@npm:^8.8.0": + version: 8.12.0 + resolution: "ajv@npm:8.12.0" + dependencies: + fast-deep-equal: ^3.1.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + uri-js: ^4.2.2 + checksum: 4dc13714e316e67537c8b31bc063f99a1d9d9a497eb4bbd55191ac0dcd5e4985bbb71570352ad6f1e76684fb6d790928f96ba3b2d4fd6e10024be9612fe3f001 + languageName: node + linkType: hard + +"ajv@npm:^6.10.0, ajv@npm:^6.12.3, ajv@npm:^6.12.4, ajv@npm:^6.12.5": + version: 6.12.6 + resolution: "ajv@npm:6.12.6" + 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 + checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 + languageName: node + linkType: hard + +"ansi-colors@npm:^4.1.1": + version: 4.1.3 + resolution: "ansi-colors@npm:4.1.3" + checksum: a9c2ec842038a1fabc7db9ece7d3177e2fe1c5dc6f0c51ecfbf5f39911427b89c00b5dc6b8bd95f82a26e9b16aaae2e83d45f060e98070ce4d1333038edceb0e + languageName: node + linkType: hard + +"ansi-escapes@npm:^4.2.1": + version: 4.3.2 + resolution: "ansi-escapes@npm:4.3.2" + dependencies: + type-fest: ^0.21.3 + checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 + languageName: node + linkType: hard + +"ansi-escapes@npm:^6.0.0": + version: 6.0.0 + resolution: "ansi-escapes@npm:6.0.0" + dependencies: + type-fest: ^3.0.0 + checksum: 1ddc0b27b1d040c3c703c9cd80ee0a103817e2f9fa8f1adf0c66e970b57543ec60effdb0bd1a396ed7182bca3b1a0d8fda60ec61fee862d353db81b1c3650a78 + languageName: node + linkType: hard + +"ansi-regex@npm:^2.1.1": + version: 2.1.1 + resolution: "ansi-regex@npm:2.1.1" + checksum: 190abd03e4ff86794f338a31795d262c1dfe8c91f7e01d04f13f646f1dcb16c5800818f886047876f1272f065570ab86b24b99089f8b68a0e11ff19aed4ca8f1 + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b + languageName: node + linkType: hard + +"ansi-regex@npm:^6.0.1": + version: 6.0.1 + resolution: "ansi-regex@npm:6.0.1" + checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 + languageName: node + linkType: hard + +"ansi-sequence-parser@npm:^1.1.0": + version: 1.1.0 + resolution: "ansi-sequence-parser@npm:1.1.0" + checksum: 75f4d3a4c555655a698aec05b5763cbddcd16ccccdbfd178fb0aa471ab74fdf98e031b875ef26e64be6a95cf970c89238744b26de6e34af97f316d5186b1df53 + languageName: node + linkType: hard + +"ansi-styles@npm:^3.2.1": + version: 3.2.1 + resolution: "ansi-styles@npm:3.2.1" + dependencies: + color-convert: ^1.9.0 + checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: ^2.0.1 + checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 + languageName: node + linkType: hard + +"ansi-styles@npm:^5.0.0": + version: 5.2.0 + resolution: "ansi-styles@npm:5.2.0" + checksum: d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 + languageName: node + linkType: hard + +"ansi-styles@npm:^6.1.0": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 + languageName: node + linkType: hard + +"any-promise@npm:^1.0.0, any-promise@npm:^1.1.0, any-promise@npm:~1.3.0": + version: 1.3.0 + resolution: "any-promise@npm:1.3.0" + checksum: 0ee8a9bdbe882c90464d75d1f55cf027f5458650c4bd1f0467e65aec38ccccda07ca5844969ee77ed46d04e7dded3eaceb027e8d32f385688523fe305fa7e1de + languageName: node + linkType: hard + +"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": + version: 3.1.3 + resolution: "anymatch@npm:3.1.3" + dependencies: + normalize-path: ^3.0.0 + picomatch: ^2.0.4 + checksum: 3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 + languageName: node + linkType: hard + +"apache-md5@npm:1.1.8": + version: 1.1.8 + resolution: "apache-md5@npm:1.1.8" + checksum: 5f93fe00a4c75c947a8ba88054cfa9c141ea13d1581515a59637d580747581345f8cee41204af354f7280439ab19120f4bec4a1ee5cf1ac7033a7a89dbb05ada + languageName: node + linkType: hard + +"aproba@npm:^1.0.3 || ^2.0.0": + version: 2.0.0 + resolution: "aproba@npm:2.0.0" + checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 + languageName: node + linkType: hard + +"are-we-there-yet@npm:^2.0.0": + version: 2.0.0 + resolution: "are-we-there-yet@npm:2.0.0" + dependencies: + delegates: ^1.0.0 + readable-stream: ^3.6.0 + checksum: 6c80b4fd04ecee6ba6e737e0b72a4b41bdc64b7d279edfc998678567ff583c8df27e27523bc789f2c99be603ffa9eaa612803da1d886962d2086e7ff6fa90c7c + languageName: node + linkType: hard + +"are-we-there-yet@npm:^3.0.0": + version: 3.0.1 + resolution: "are-we-there-yet@npm:3.0.1" + dependencies: + delegates: ^1.0.0 + readable-stream: ^3.6.0 + checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 + languageName: node + linkType: hard + +"argparse@npm:^1.0.7": + version: 1.0.10 + resolution: "argparse@npm:1.0.10" + dependencies: + sprintf-js: ~1.0.2 + checksum: 7ca6e45583a28de7258e39e13d81e925cfa25d7d4aacbf806a382d3c02fcb13403a07fb8aeef949f10a7cfe4a62da0e2e807b348a5980554cc28ee573ef95945 + languageName: node + linkType: hard + +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced + languageName: node + linkType: hard + +"array-differ@npm:^3.0.0": + version: 3.0.0 + resolution: "array-differ@npm:3.0.0" + checksum: 117edd9df5c1530bd116c6e8eea891d4bd02850fd89b1b36e532b6540e47ca620a373b81feca1c62d1395d9ae601516ba538abe5e8172d41091da2c546b05fb7 + languageName: node + linkType: hard + +"array-flatten@npm:1.1.1": + version: 1.1.1 + resolution: "array-flatten@npm:1.1.1" + checksum: a9925bf3512d9dce202112965de90c222cd59a4fbfce68a0951d25d965cf44642931f40aac72309c41f12df19afa010ecadceb07cfff9ccc1621e99d89ab5f3b + languageName: node + linkType: hard + +"array-ify@npm:^1.0.0": + version: 1.0.0 + resolution: "array-ify@npm:1.0.0" + checksum: c0502015b319c93dd4484f18036bcc4b654eb76a4aa1f04afbcef11ac918859bb1f5d71ba1f0f1141770db9eef1a4f40f1761753650873068010bbf7bcdae4a4 + languageName: node + linkType: hard + +"array-includes@npm:^3.1.5, array-includes@npm:^3.1.6": + version: 3.1.6 + resolution: "array-includes@npm:3.1.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + get-intrinsic: ^1.1.3 + is-string: ^1.0.7 + checksum: f22f8cd8ba8a6448d91eebdc69f04e4e55085d09232b5216ee2d476dab3ef59984e8d1889e662c6a0ed939dcb1b57fd05b2c0209c3370942fc41b752c82a2ca5 + languageName: node + linkType: hard + +"array-union@npm:^2.1.0": + version: 2.1.0 + resolution: "array-union@npm:2.1.0" + checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d + languageName: node + linkType: hard + +"array.prototype.flatmap@npm:^1.3.1": + version: 1.3.1 + resolution: "array.prototype.flatmap@npm:1.3.1" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + es-shim-unscopables: ^1.0.0 + checksum: 8c1c43a4995f12cf12523436da28515184c753807b3f0bc2ca6c075f71c470b099e2090cc67dba8e5280958fea401c1d0c59e1db0143272aef6cd1103921a987 + languageName: node + linkType: hard + +"array.prototype.tosorted@npm:^1.1.1": + version: 1.1.1 + resolution: "array.prototype.tosorted@npm:1.1.1" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + es-shim-unscopables: ^1.0.0 + get-intrinsic: ^1.1.3 + checksum: 7923324a67e70a2fc0a6e40237405d92395e45ebd76f5cb89c2a5cf1e66b47aca6baacd0cd628ffd88830b90d47fff268071493d09c9ae123645613dac2c2ca3 + languageName: node + linkType: hard + +"arrify@npm:^1.0.1": + version: 1.0.1 + resolution: "arrify@npm:1.0.1" + checksum: 745075dd4a4624ff0225c331dacb99be501a515d39bcb7c84d24660314a6ec28e68131b137e6f7e16318170842ce97538cd298fc4cd6b2cc798e0b957f2747e7 + languageName: node + linkType: hard + +"arrify@npm:^2.0.1": + version: 2.0.1 + resolution: "arrify@npm:2.0.1" + checksum: 067c4c1afd182806a82e4c1cb8acee16ab8b5284fbca1ce29408e6e91281c36bb5b612f6ddfbd40a0f7a7e0c75bf2696eb94c027f6e328d6e9c52465c98e4209 + languageName: node + linkType: hard + +"asap@npm:~2.0.3": + version: 2.0.6 + resolution: "asap@npm:2.0.6" + checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d + languageName: node + linkType: hard + +"asn1@npm:~0.2.3": + version: 0.2.6 + resolution: "asn1@npm:0.2.6" + dependencies: + safer-buffer: ~2.1.0 + checksum: 39f2ae343b03c15ad4f238ba561e626602a3de8d94ae536c46a4a93e69578826305366dc09fbb9b56aec39b4982a463682f259c38e59f6fa380cd72cd61e493d + languageName: node + linkType: hard + +"assert-plus@npm:1.0.0, assert-plus@npm:^1.0.0": + version: 1.0.0 + resolution: "assert-plus@npm:1.0.0" + checksum: 19b4340cb8f0e6a981c07225eacac0e9d52c2644c080198765d63398f0075f83bbc0c8e95474d54224e297555ad0d631c1dcd058adb1ddc2437b41a6b424ac64 + languageName: node + linkType: hard + +"astral-regex@npm:^2.0.0": + version: 2.0.0 + resolution: "astral-regex@npm:2.0.0" + checksum: 876231688c66400473ba505731df37ea436e574dd524520294cc3bbc54ea40334865e01fa0d074d74d036ee874ee7e62f486ea38bc421ee8e6a871c06f011766 + languageName: node + linkType: hard + +"async@npm:3.2.4, async@npm:^3.2.3": + version: 3.2.4 + resolution: "async@npm:3.2.4" + checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 + languageName: node + linkType: hard + +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be + languageName: node + linkType: hard + +"atomic-sleep@npm:^1.0.0": + version: 1.0.0 + resolution: "atomic-sleep@npm:1.0.0" + checksum: b95275afb2f80732f22f43a60178430c468906a415a7ff18bcd0feeebc8eec3930b51250aeda91a476062a90e07132b43a1794e8d8ffcf9b650e8139be75fa36 + languageName: node + linkType: hard + +"available-typed-arrays@npm:^1.0.5": + version: 1.0.5 + resolution: "available-typed-arrays@npm:1.0.5" + checksum: 20eb47b3cefd7db027b9bbb993c658abd36d4edd3fe1060e83699a03ee275b0c9b216cc076ff3f2db29073225fb70e7613987af14269ac1fe2a19803ccc97f1a + languageName: node + linkType: hard + +"aws-sign2@npm:~0.7.0": + version: 0.7.0 + resolution: "aws-sign2@npm:0.7.0" + checksum: b148b0bb0778098ad8cf7e5fc619768bcb51236707ca1d3e5b49e41b171166d8be9fdc2ea2ae43d7decf02989d0aaa3a9c4caa6f320af95d684de9b548a71525 + languageName: node + linkType: hard + +"aws4@npm:^1.8.0": + version: 1.12.0 + resolution: "aws4@npm:1.12.0" + checksum: 68f79708ac7c335992730bf638286a3ee0a645cf12575d557860100767c500c08b30e24726b9f03265d74116417f628af78509e1333575e9f8d52a80edfe8cbc + languageName: node + linkType: hard + +"axios@npm:^1.0.0": + version: 1.3.4 + resolution: "axios@npm:1.3.4" + dependencies: + follow-redirects: ^1.15.0 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: 7440edefcf8498bc3cdf39de00443e8101f249972c83b739c6e880d9d669fea9486372dbe8739e88b3bf8bb1ad15f6106693f206f078f4516fe8fd47b1c3093c + languageName: node + linkType: hard + +"babel-jest@npm:^29.5.0": + version: 29.5.0 + resolution: "babel-jest@npm:29.5.0" + dependencies: + "@jest/transform": ^29.5.0 + "@types/babel__core": ^7.1.14 + babel-plugin-istanbul: ^6.1.1 + babel-preset-jest: ^29.5.0 + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + slash: ^3.0.0 + peerDependencies: + "@babel/core": ^7.8.0 + checksum: eafb6d37deb71f0c80bf3c80215aa46732153e5e8bcd73f6ff47d92e5c0c98c8f7f75995d0efec6289c371edad3693cd8fa2367b0661c4deb71a3a7117267ede + languageName: node + linkType: hard + +"babel-plugin-istanbul@npm:^6.1.1": + version: 6.1.1 + resolution: "babel-plugin-istanbul@npm:6.1.1" + dependencies: + "@babel/helper-plugin-utils": ^7.0.0 + "@istanbuljs/load-nyc-config": ^1.0.0 + "@istanbuljs/schema": ^0.1.2 + istanbul-lib-instrument: ^5.0.4 + test-exclude: ^6.0.0 + checksum: cb4fd95738219f232f0aece1116628cccff16db891713c4ccb501cddbbf9272951a5df81f2f2658dfdf4b3e7b236a9d5cbcf04d5d8c07dd5077297339598061a + languageName: node + linkType: hard + +"babel-plugin-jest-hoist@npm:^29.5.0": + version: 29.5.0 + resolution: "babel-plugin-jest-hoist@npm:29.5.0" + dependencies: + "@babel/template": ^7.3.3 + "@babel/types": ^7.3.3 + "@types/babel__core": ^7.1.14 + "@types/babel__traverse": ^7.0.6 + checksum: 099b5254073b6bc985b6d2d045ad26fb8ed30ff8ae6404c4fe8ee7cd0e98a820f69e3dfb871c7c65aae0f4b65af77046244c07bb92d49ef9005c90eedf681539 + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs2@npm:^0.3.3": + version: 0.3.3 + resolution: "babel-plugin-polyfill-corejs2@npm:0.3.3" + dependencies: + "@babel/compat-data": ^7.17.7 + "@babel/helper-define-polyfill-provider": ^0.3.3 + semver: ^6.1.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7db3044993f3dddb3cc3d407bc82e640964a3bfe22de05d90e1f8f7a5cb71460011ab136d3c03c6c1ba428359ebf635688cd6205e28d0469bba221985f5c6179 + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs3@npm:^0.6.0": + version: 0.6.0 + resolution: "babel-plugin-polyfill-corejs3@npm:0.6.0" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.3.3 + core-js-compat: ^3.25.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 470bb8c59f7c0912bd77fe1b5a2e72f349b3f65bbdee1d60d6eb7e1f4a085c6f24b2dd5ab4ac6c2df6444a96b070ef6790eccc9edb6a2668c60d33133bfb62c6 + languageName: node + linkType: hard + +"babel-plugin-polyfill-regenerator@npm:^0.4.1": + version: 0.4.1 + resolution: "babel-plugin-polyfill-regenerator@npm:0.4.1" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.3.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ab0355efbad17d29492503230387679dfb780b63b25408990d2e4cf421012dae61d6199ddc309f4d2409ce4e9d3002d187702700dd8f4f8770ebbba651ed066c + languageName: node + linkType: hard + +"babel-preset-current-node-syntax@npm:^1.0.0": + version: 1.0.1 + resolution: "babel-preset-current-node-syntax@npm:1.0.1" + dependencies: + "@babel/plugin-syntax-async-generators": ^7.8.4 + "@babel/plugin-syntax-bigint": ^7.8.3 + "@babel/plugin-syntax-class-properties": ^7.8.3 + "@babel/plugin-syntax-import-meta": ^7.8.3 + "@babel/plugin-syntax-json-strings": ^7.8.3 + "@babel/plugin-syntax-logical-assignment-operators": ^7.8.3 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + "@babel/plugin-syntax-numeric-separator": ^7.8.3 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + "@babel/plugin-syntax-top-level-await": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: d118c2742498c5492c095bc8541f4076b253e705b5f1ad9a2e7d302d81a84866f0070346662355c8e25fc02caa28dc2da8d69bcd67794a0d60c4d6fab6913cc8 + languageName: node + linkType: hard + +"babel-preset-jest@npm:^29.5.0": + version: 29.5.0 + resolution: "babel-preset-jest@npm:29.5.0" + dependencies: + babel-plugin-jest-hoist: ^29.5.0 + babel-preset-current-node-syntax: ^1.0.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 5566ca2762766c9319b4973d018d2fa08c0fcf6415c72cc54f4c8e7199e851ea8f5e6c6730f03ed7ed44fc8beefa959dd15911f2647dee47c615ff4faeddb1ad + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 + languageName: node + linkType: hard + +"balanced-match@npm:^2.0.0": + version: 2.0.0 + resolution: "balanced-match@npm:2.0.0" + checksum: 9a5caad6a292c5df164cc6d0c38e0eedf9a1413f42e5fece733640949d74d0052cfa9587c1a1681f772147fb79be495121325a649526957fd75b3a216d1fbc68 + languageName: node + linkType: hard + +"base16@npm:^1.0.0": + version: 1.0.0 + resolution: "base16@npm:1.0.0" + checksum: 0cd449a2db0f0f957e4b6b57e33bc43c9e20d4f1dd744065db94b5da35e8e71fa4dc4bc7a901e59a84d5f8b6936e3c520e2471787f667fc155fb0f50d8540f5d + languageName: node + linkType: hard + +"base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 + languageName: node + linkType: hard + +"bcrypt-pbkdf@npm:^1.0.0": + version: 1.0.2 + resolution: "bcrypt-pbkdf@npm:1.0.2" + dependencies: + tweetnacl: ^0.14.3 + checksum: 4edfc9fe7d07019609ccf797a2af28351736e9d012c8402a07120c4453a3b789a15f2ee1530dc49eee8f7eb9379331a8dd4b3766042b9e502f74a68e7f662291 + languageName: node + linkType: hard + +"bcryptjs@npm:2.4.3": + version: 2.4.3 + resolution: "bcryptjs@npm:2.4.3" + checksum: 0e80ed852a41f5dfb1853f53ee14a7390b0ef263ce05dba6e2ef3cd919dfad025a7c21ebcfe5bc7fa04b100990edf90c7a877ff7fe623d3e479753253131b629 + languageName: node + linkType: hard + +"before-after-hook@npm:^2.2.0": + version: 2.2.3 + resolution: "before-after-hook@npm:2.2.3" + checksum: a1a2430976d9bdab4cd89cb50d27fa86b19e2b41812bf1315923b0cba03371ebca99449809226425dd3bcef20e010db61abdaff549278e111d6480034bebae87 + languageName: node + linkType: hard + +"big-integer@npm:^1.6.44": + version: 1.6.51 + resolution: "big-integer@npm:1.6.51" + checksum: 3d444173d1b2e20747e2c175568bedeebd8315b0637ea95d75fd27830d3b8e8ba36c6af40374f36bdaea7b5de376dcada1b07587cb2a79a928fccdb6e6e3c518 + languageName: node + linkType: hard + +"big.js@npm:^5.2.2": + version: 5.2.2 + resolution: "big.js@npm:5.2.2" + checksum: b89b6e8419b097a8fb4ed2399a1931a68c612bce3cfd5ca8c214b2d017531191070f990598de2fc6f3f993d91c0f08aa82697717f6b3b8732c9731866d233c9e + languageName: node + linkType: hard + +"binary-extensions@npm:^2.0.0": + version: 2.2.0 + resolution: "binary-extensions@npm:2.2.0" + checksum: ccd267956c58d2315f5d3ea6757cf09863c5fc703e50fbeb13a7dc849b812ef76e3cf9ca8f35a0c48498776a7478d7b4a0418e1e2b8cb9cb9731f2922aaad7f8 + languageName: node + linkType: hard + +"bl@npm:^4.0.3, bl@npm:^4.1.0": + version: 4.1.0 + resolution: "bl@npm:4.1.0" + dependencies: + buffer: ^5.5.0 + inherits: ^2.0.4 + readable-stream: ^3.4.0 + checksum: 9e8521fa7e83aa9427c6f8ccdcba6e8167ef30cc9a22df26effcc5ab682ef91d2cbc23a239f945d099289e4bbcfae7a192e9c28c84c6202e710a0dfec3722662 + languageName: node + linkType: hard + +"bl@npm:^5.0.0": + version: 5.1.0 + resolution: "bl@npm:5.1.0" + dependencies: + buffer: ^6.0.3 + inherits: ^2.0.4 + readable-stream: ^3.4.0 + checksum: a7a438ee0bc540e80b8eb68cc1ad759a9c87df06874a99411d701d01cc0b36f30cd20050512ac3e77090138890960e07bfee724f3ee6619bb39a569f5cc3b1bc + languageName: node + linkType: hard + +"body-parser@npm:1.20.1": + version: 1.20.1 + resolution: "body-parser@npm:1.20.1" + dependencies: + bytes: 3.1.2 + content-type: ~1.0.4 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: ~1.6.18 + unpipe: 1.0.0 + checksum: f1050dbac3bede6a78f0b87947a8d548ce43f91ccc718a50dd774f3c81f2d8b04693e52acf62659fad23101827dd318da1fb1363444ff9a8482b886a3e4a5266 + languageName: node + linkType: hard + +"body-parser@npm:1.20.2": + version: 1.20.2 + resolution: "body-parser@npm:1.20.2" + dependencies: + bytes: 3.1.2 + content-type: ~1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.2 + type-is: ~1.6.18 + unpipe: 1.0.0 + checksum: 14d37ec638ab5c93f6099ecaed7f28f890d222c650c69306872e00b9efa081ff6c596cd9afb9930656aae4d6c4e1c17537bea12bb73c87a217cb3cfea8896737 + languageName: node + linkType: hard + +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 + languageName: node + linkType: hard + +"bplist-parser@npm:^0.2.0": + version: 0.2.0 + resolution: "bplist-parser@npm:0.2.0" + dependencies: + big-integer: ^1.6.44 + checksum: d5339dd16afc51de6c88f88f58a45b72ed6a06aa31f5557d09877575f220b7c1d3fbe375da0b62e6a10d4b8ed80523567e351f24014f5bc886ad523758142cdd + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" + dependencies: + balanced-match: ^1.0.0 + concat-map: 0.0.1 + checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + languageName: node + linkType: hard + +"brace-expansion@npm:^2.0.1": + version: 2.0.1 + resolution: "brace-expansion@npm:2.0.1" + dependencies: + balanced-match: ^1.0.0 + checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 + languageName: node + linkType: hard + +"braces@npm:^3.0.2, braces@npm:~3.0.2": + version: 3.0.2 + resolution: "braces@npm:3.0.2" + dependencies: + fill-range: ^7.0.1 + checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459 + languageName: node + linkType: hard + +"browserslist@npm:^4.14.5, browserslist@npm:^4.21.3, browserslist@npm:^4.21.5": + version: 4.21.5 + resolution: "browserslist@npm:4.21.5" + dependencies: + caniuse-lite: ^1.0.30001449 + electron-to-chromium: ^1.4.284 + node-releases: ^2.0.8 + update-browserslist-db: ^1.0.10 + bin: + browserslist: cli.js + checksum: 9755986b22e73a6a1497fd8797aedd88e04270be33ce66ed5d85a1c8a798292a65e222b0f251bafa1c2522261e237d73b08b58689d4920a607e5a53d56dc4706 + languageName: node + linkType: hard + +"bs-logger@npm:0.x": + version: 0.2.6 + resolution: "bs-logger@npm:0.2.6" + dependencies: + fast-json-stable-stringify: 2.x + checksum: d34bdaf68c64bd099ab97c3ea608c9ae7d3f5faa1178b3f3f345acd94e852e608b2d4f9103fb2e503f5e69780e98293df41691b84be909b41cf5045374d54606 + languageName: node + linkType: hard + +"bser@npm:2.1.1": + version: 2.1.1 + resolution: "bser@npm:2.1.1" + dependencies: + node-int64: ^0.4.0 + checksum: 9ba4dc58ce86300c862bffc3ae91f00b2a03b01ee07f3564beeeaf82aa243b8b03ba53f123b0b842c190d4399b94697970c8e7cf7b1ea44b61aa28c3526a4449 + languageName: node + linkType: hard + +"buffer-equal-constant-time@npm:1.0.1": + version: 1.0.1 + resolution: "buffer-equal-constant-time@npm:1.0.1" + checksum: 80bb945f5d782a56f374b292770901065bad21420e34936ecbe949e57724b4a13874f735850dd1cc61f078773c4fb5493a41391e7bda40d1fa388d6bd80daaab + languageName: node + linkType: hard + +"buffer-from@npm:^1.0.0": + version: 1.1.2 + resolution: "buffer-from@npm:1.1.2" + checksum: 0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb + languageName: node + linkType: hard + +"buffer@npm:^5.5.0": + version: 5.7.1 + resolution: "buffer@npm:5.7.1" + dependencies: + base64-js: ^1.3.1 + ieee754: ^1.1.13 + checksum: e2cf8429e1c4c7b8cbd30834ac09bd61da46ce35f5c22a78e6c2f04497d6d25541b16881e30a019c6fd3154150650ccee27a308eff3e26229d788bbdeb08ab84 + languageName: node + linkType: hard + +"buffer@npm:^6.0.3": + version: 6.0.3 + resolution: "buffer@npm:6.0.3" + dependencies: + base64-js: ^1.3.1 + ieee754: ^1.2.1 + checksum: 5ad23293d9a731e4318e420025800b42bf0d264004c0286c8cc010af7a270c7a0f6522e84f54b9ad65cbd6db20b8badbfd8d2ebf4f80fa03dab093b89e68c3f9 + languageName: node + linkType: hard + +"builtins@npm:^1.0.3": + version: 1.0.3 + resolution: "builtins@npm:1.0.3" + checksum: 47ce94f7eee0e644969da1f1a28e5f29bd2e48b25b2bbb61164c345881086e29464ccb1fb88dbc155ea26e8b1f5fc8a923b26c8c1ed0935b67b644d410674513 + languageName: node + linkType: hard + +"builtins@npm:^5.0.0": + version: 5.0.1 + resolution: "builtins@npm:5.0.1" + dependencies: + semver: ^7.0.0 + checksum: 66d204657fe36522822a95b288943ad11b58f5eaede235b11d8c4edaa28ce4800087d44a2681524c340494aadb120a0068011acabe99d30e8f11a7d826d83515 + languageName: node + linkType: hard + +"bundle-name@npm:^3.0.0": + version: 3.0.0 + resolution: "bundle-name@npm:3.0.0" + dependencies: + run-applescript: ^5.0.0 + checksum: edf2b1fbe6096ed32e7566947ace2ea937ee427391744d7510a2880c4b9a5b3543d3f6c551236a29e5c87d3195f8e2912516290e638c15bcbede7b37cc375615 + languageName: node + linkType: hard + +"byte-size@npm:8.1.1": + version: 8.1.1 + resolution: "byte-size@npm:8.1.1" + checksum: 65f00881ffd3c2b282fe848ed954fa4ff8363eaa3f652102510668b90b3fad04d81889486ee1b641ee0d8c8b75cf32201f3b309e6b5fbb6cc869b48a91b62d3e + languageName: node + linkType: hard + +"bytes@npm:3.0.0": + version: 3.0.0 + resolution: "bytes@npm:3.0.0" + checksum: a2b386dd8188849a5325f58eef69c3b73c51801c08ffc6963eddc9be244089ba32d19347caf6d145c86f315ae1b1fc7061a32b0c1aa6379e6a719090287ed101 + languageName: node + linkType: hard + +"bytes@npm:3.1.2": + version: 3.1.2 + resolution: "bytes@npm:3.1.2" + checksum: e4bcd3948d289c5127591fbedf10c0b639ccbf00243504e4e127374a15c3bc8eed0d28d4aaab08ff6f1cf2abc0cce6ba3085ed32f4f90e82a5683ce0014e1b6e + languageName: node + linkType: hard + +"cacache@npm:^16.1.0": + version: 16.1.3 + resolution: "cacache@npm:16.1.3" + dependencies: + "@npmcli/fs": ^2.1.0 + "@npmcli/move-file": ^2.0.0 + chownr: ^2.0.0 + fs-minipass: ^2.1.0 + glob: ^8.0.1 + infer-owner: ^1.0.4 + lru-cache: ^7.7.1 + minipass: ^3.1.6 + minipass-collect: ^1.0.2 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + mkdirp: ^1.0.4 + p-map: ^4.0.0 + promise-inflight: ^1.0.1 + rimraf: ^3.0.2 + ssri: ^9.0.0 + tar: ^6.1.11 + unique-filename: ^2.0.0 + checksum: d91409e6e57d7d9a3a25e5dcc589c84e75b178ae8ea7de05cbf6b783f77a5fae938f6e8fda6f5257ed70000be27a681e1e44829251bfffe4c10216002f8f14e6 + languageName: node + linkType: hard + +"cacache@npm:^17.0.0": + version: 17.1.3 + resolution: "cacache@npm:17.1.3" + dependencies: + "@npmcli/fs": ^3.1.0 + fs-minipass: ^3.0.0 + glob: ^10.2.2 + lru-cache: ^7.7.1 + minipass: ^5.0.0 + minipass-collect: ^1.0.2 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + p-map: ^4.0.0 + ssri: ^10.0.0 + tar: ^6.1.11 + unique-filename: ^3.0.0 + checksum: 385756781e1e21af089160d89d7462b7ed9883c978e848c7075b90b73cb823680e66092d61513050164588387d2ca87dd6d910e28d64bc13a9ac82cd8580c796 + languageName: node + linkType: hard + +"cacheable-lookup@npm:^5.0.3": + version: 5.0.4 + resolution: "cacheable-lookup@npm:5.0.4" + checksum: 763e02cf9196bc9afccacd8c418d942fc2677f22261969a4c2c2e760fa44a2351a81557bd908291c3921fe9beb10b976ba8fa50c5ca837c5a0dd945f16468f2d + languageName: node + linkType: hard + +"cacheable-request@npm:^7.0.2": + version: 7.0.2 + resolution: "cacheable-request@npm:7.0.2" + dependencies: + clone-response: ^1.0.2 + get-stream: ^5.1.0 + http-cache-semantics: ^4.0.0 + keyv: ^4.0.0 + lowercase-keys: ^2.0.0 + normalize-url: ^6.0.1 + responselike: ^2.0.0 + checksum: 6152813982945a5c9989cb457a6c499f12edcc7ade323d2fbfd759abc860bdbd1306e08096916bb413c3c47e812f8e4c0a0cc1e112c8ce94381a960f115bc77f + languageName: node + linkType: hard + +"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind@npm:1.0.2" + dependencies: + function-bind: ^1.1.1 + get-intrinsic: ^1.0.2 + checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0 + languageName: node + linkType: hard + +"call-me-maybe@npm:^1.0.1": + version: 1.0.2 + resolution: "call-me-maybe@npm:1.0.2" + checksum: 42ff2d0bed5b207e3f0122589162eaaa47ba618f79ad2382fe0ba14d9e49fbf901099a6227440acc5946f86a4953e8aa2d242b330b0a5de4d090bb18f8935cae + languageName: node + linkType: hard + +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 + languageName: node + linkType: hard + +"camel-case@npm:^4.1.1, camel-case@npm:^4.1.2": + version: 4.1.2 + resolution: "camel-case@npm:4.1.2" + dependencies: + pascal-case: ^3.1.2 + tslib: ^2.0.3 + checksum: bcbd25cd253b3cbc69be3f535750137dbf2beb70f093bdc575f73f800acc8443d34fd52ab8f0a2413c34f1e8203139ffc88428d8863e4dfe530cfb257a379ad6 + languageName: node + linkType: hard + +"camelcase-keys@npm:^6.2.2": + version: 6.2.2 + resolution: "camelcase-keys@npm:6.2.2" + dependencies: + camelcase: ^5.3.1 + map-obj: ^4.0.0 + quick-lru: ^4.0.1 + checksum: 43c9af1adf840471e54c68ab3e5fe8a62719a6b7dbf4e2e86886b7b0ff96112c945736342b837bd2529ec9d1c7d1934e5653318478d98e0cf22c475c04658e2a + languageName: node + linkType: hard + +"camelcase-keys@npm:^7.0.0": + version: 7.0.2 + resolution: "camelcase-keys@npm:7.0.2" + dependencies: + camelcase: ^6.3.0 + map-obj: ^4.1.0 + quick-lru: ^5.1.1 + type-fest: ^1.2.1 + checksum: b5821cc48dd00e8398a30c5d6547f06837ab44de123f1b3a603d0a03399722b2fc67a485a7e47106eb02ef543c3b50c5ebaabc1242cde4b63a267c3258d2365b + languageName: node + linkType: hard + +"camelcase@npm:^5.3.1": + version: 5.3.1 + resolution: "camelcase@npm:5.3.1" + checksum: e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b + languageName: node + linkType: hard + +"camelcase@npm:^6.2.0, camelcase@npm:^6.3.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001449": + version: 1.0.30001464 + resolution: "caniuse-lite@npm:1.0.30001464" + checksum: 67cdee102c1660d62d7b9dbd4740bb7af096236618f2509fd2e0039d50db5f02fb87c21d90b6d573fdcf50deaf3c84503d009e871502b5c221d0ba1dec18ba11 + languageName: node + linkType: hard + +"canvas@npm:^2.11.2": + version: 2.11.2 + resolution: "canvas@npm:2.11.2" + dependencies: + "@mapbox/node-pre-gyp": ^1.0.0 + nan: ^2.17.0 + node-gyp: latest + simple-get: ^3.0.3 + checksum: 61e554aef80022841dc836964534082ec21435928498032562089dfb7736215f039c7d99ee546b0cf10780232d9bf310950f8b4d489dc394e0fb6f6adfc97994 + languageName: node + linkType: hard + +"caseless@npm:~0.12.0": + version: 0.12.0 + resolution: "caseless@npm:0.12.0" + checksum: b43bd4c440aa1e8ee6baefee8063b4850fd0d7b378f6aabc796c9ec8cb26d27fb30b46885350777d9bd079c5256c0e1329ad0dc7c2817e0bb466810ebb353751 + languageName: node + linkType: hard + +"chalk@npm:4.1.0": + version: 4.1.0 + resolution: "chalk@npm:4.1.0" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: 5561c7b4c063badee3e16d04bce50bd033e1be1bf4c6948639275683ffa7a1993c44639b43c22b1c505f0f813a24b1889037eb182546b48946f9fe7cdd0e7d13 + languageName: node + linkType: hard + +"chalk@npm:^2.0.0, chalk@npm:^2.3.0": + version: 2.4.2 + resolution: "chalk@npm:2.4.2" + dependencies: + ansi-styles: ^3.2.1 + escape-string-regexp: ^1.0.5 + supports-color: ^5.3.0 + checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 + languageName: node + linkType: hard + +"chalk@npm:^3.0.0": + version: 3.0.0 + resolution: "chalk@npm:3.0.0" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505 + languageName: node + linkType: hard + +"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + languageName: node + linkType: hard + +"chalk@npm:^5.0.0, chalk@npm:^5.1.2": + version: 5.2.0 + resolution: "chalk@npm:5.2.0" + checksum: 03d8060277de6cf2fd567dc25fcf770593eb5bb85f460ce443e49255a30ff1242edd0c90a06a03803b0466ff0687a939b41db1757bec987113e83de89a003caa + languageName: node + linkType: hard + +"char-regex@npm:^1.0.2": + version: 1.0.2 + resolution: "char-regex@npm:1.0.2" + checksum: b563e4b6039b15213114626621e7a3d12f31008bdce20f9c741d69987f62aeaace7ec30f6018890ad77b2e9b4d95324c9f5acfca58a9441e3b1dcdd1e2525d17 + languageName: node + linkType: hard + +"chardet@npm:^0.7.0": + version: 0.7.0 + resolution: "chardet@npm:0.7.0" + checksum: 6fd5da1f5d18ff5712c1e0aed41da200d7c51c28f11b36ee3c7b483f3696dabc08927fc6b227735eb8f0e1215c9a8abd8154637f3eff8cada5959df7f58b024d + languageName: node + linkType: hard + +"chevrotain@npm:^9.1.0": + version: 9.1.0 + resolution: "chevrotain@npm:9.1.0" + dependencies: + "@chevrotain/types": ^9.1.0 + "@chevrotain/utils": ^9.1.0 + regexp-to-ast: 0.5.0 + checksum: 632d0d7c69081e3cc3a08c071cb738c46499a05f1a513b7f9101f7a9b5570d6ee62cac5ba506659a85bf9e71e1029c462dbb7bd9fe1bfe019b6c1879ca29c525 + languageName: node + linkType: hard + +"child_process@npm:~1.0.2": + version: 1.0.2 + resolution: "child_process@npm:1.0.2" + checksum: bd814d82bc8c6e85ed6fb157878978121cd03b5296c09f6135fa3d081fd9a6a617a6d509c50397711df713af403331241a9c0397a7fad30672051485e156c2a1 + languageName: node + linkType: hard + +"chokidar@npm:^3.4.0": + version: 3.5.3 + resolution: "chokidar@npm:3.5.3" + dependencies: + anymatch: ~3.1.2 + braces: ~3.0.2 + fsevents: ~2.3.2 + glob-parent: ~5.1.2 + is-binary-path: ~2.1.0 + is-glob: ~4.0.1 + normalize-path: ~3.0.0 + readdirp: ~3.6.0 + dependenciesMeta: + fsevents: + optional: true + checksum: b49fcde40176ba007ff361b198a2d35df60d9bb2a5aab228279eb810feae9294a6b4649ab15981304447afe1e6ffbf4788ad5db77235dc770ab777c6e771980c + languageName: node + linkType: hard + +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f + languageName: node + linkType: hard + +"chrome-trace-event@npm:^1.0.2": + version: 1.0.3 + resolution: "chrome-trace-event@npm:1.0.3" + checksum: cb8b1fc7e881aaef973bd0c4a43cd353c2ad8323fb471a041e64f7c2dd849cde4aad15f8b753331a32dda45c973f032c8a03b8177fc85d60eaa75e91e08bfb97 + languageName: node + linkType: hard + +"ci-info@npm:^3.2.0, ci-info@npm:^3.6.1": + version: 3.8.0 + resolution: "ci-info@npm:3.8.0" + checksum: d0a4d3160497cae54294974a7246202244fff031b0a6ea20dd57b10ec510aa17399c41a1b0982142c105f3255aff2173e5c0dd7302ee1b2f28ba3debda375098 + languageName: node + linkType: hard + +"cjs-module-lexer@npm:^1.0.0": + version: 1.2.2 + resolution: "cjs-module-lexer@npm:1.2.2" + checksum: 977f3f042bd4f08e368c890d91eecfbc4f91da0bc009a3c557bc4dfbf32022ad1141244ac1178d44de70fc9f3dea7add7cd9a658a34b9fae98a55d8f92331ce5 + languageName: node + linkType: hard + +"clean-css@npm:^4.2.3": + version: 4.2.4 + resolution: "clean-css@npm:4.2.4" + dependencies: + source-map: ~0.6.0 + checksum: 045ff6fcf4b5c76a084b24e1633e0c78a13b24080338fc8544565a9751559aa32ff4ee5886d9e52c18a644a6ff119bd8e37bc58e574377c05382a1fb7dbe39f8 + languageName: node + linkType: hard + +"clean-css@npm:^5.2.2": + version: 5.3.2 + resolution: "clean-css@npm:5.3.2" + dependencies: + source-map: ~0.6.0 + checksum: 8787b281acc9878f309b5f835d410085deedfd4e126472666773040a6a8a72f472a1d24185947d23b87b1c419bf2c5ed429395d5c5ff8279c98b05d8011e9758 + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 + languageName: node + linkType: hard + +"cli-color@npm:^1.4.0": + version: 1.4.0 + resolution: "cli-color@npm:1.4.0" + dependencies: + ansi-regex: ^2.1.1 + d: 1 + es5-ext: ^0.10.46 + es6-iterator: ^2.0.3 + memoizee: ^0.4.14 + timers-ext: ^0.1.5 + checksum: 5e840cf68c913f3c4e9eb889e45ea8c26260f6253407ee3a95e11ba317454638e7c41b9fd641a1305b9a6d84e996a86c8468c112695290262f6066138a6445f4 + languageName: node + linkType: hard + +"cli-cursor@npm:3.1.0, cli-cursor@npm:^3.1.0": + version: 3.1.0 + resolution: "cli-cursor@npm:3.1.0" + dependencies: + restore-cursor: ^3.1.0 + checksum: 2692784c6cd2fd85cfdbd11f53aea73a463a6d64a77c3e098b2b4697a20443f430c220629e1ca3b195ea5ac4a97a74c2ee411f3807abf6df2b66211fec0c0a29 + languageName: node + linkType: hard + +"cli-cursor@npm:^4.0.0": + version: 4.0.0 + resolution: "cli-cursor@npm:4.0.0" + dependencies: + restore-cursor: ^4.0.0 + checksum: ab3f3ea2076e2176a1da29f9d64f72ec3efad51c0960898b56c8a17671365c26e67b735920530eaf7328d61f8bd41c27f46b9cf6e4e10fe2fa44b5e8c0e392cc + languageName: node + linkType: hard + +"cli-spinners@npm:2.6.1, cli-spinners@npm:^2.5.0, cli-spinners@npm:^2.6.1": + version: 2.6.1 + resolution: "cli-spinners@npm:2.6.1" + checksum: 423409baaa7a58e5104b46ca1745fbfc5888bbd0b0c5a626e052ae1387060839c8efd512fb127e25769b3dc9562db1dc1b5add6e0b93b7ef64f477feb6416a45 + languageName: node + linkType: hard + +"cli-width@npm:^3.0.0": + version: 3.0.0 + resolution: "cli-width@npm:3.0.0" + checksum: 4c94af3769367a70e11ed69aa6095f1c600c0ff510f3921ab4045af961820d57c0233acfa8b6396037391f31b4c397e1f614d234294f979ff61430a6c166c3f6 + languageName: node + linkType: hard + +"cli-width@npm:^4.0.0": + version: 4.0.0 + resolution: "cli-width@npm:4.0.0" + checksum: 1ec12311217cc8b2d018646a58b61424d2348def598fb58ba2c32e28f0bcb59a35cef168110311cefe3340abf00e5171b351de6c3e2c084bd1642e6e2a9e144e + languageName: node + linkType: hard + +"clipanion@npm:3.2.0": + version: 3.2.0 + resolution: "clipanion@npm:3.2.0" + dependencies: + typanion: ^3.8.0 + peerDependencies: + typanion: "*" + checksum: e28e6f0d48aecff86097823c604aa486082d76d2a5d3abc71069a0d9f3338af769fd7c6634b2f444c5b1aac0743b503325cc0b30552c094c01ebc602631b273d + languageName: node + linkType: hard + +"clipanion@npm:3.2.0-rc.4": + version: 3.2.0-rc.4 + resolution: "clipanion@npm:3.2.0-rc.4" + dependencies: + typanion: ^3.3.1 + peerDependencies: + typanion: "*" + checksum: c9d8ba9e16dca3016c32f42107a7602c52c9176626e0c815113c32b614ca125a9707221ec9df9c0a06e9741a23e0664153db1522c4f80b29f4b4d427fba002be + languageName: node + linkType: hard + +"cliui@npm:^7.0.2": + version: 7.0.4 + resolution: "cliui@npm:7.0.4" + dependencies: + string-width: ^4.2.0 + strip-ansi: ^6.0.0 + wrap-ansi: ^7.0.0 + checksum: ce2e8f578a4813806788ac399b9e866297740eecd4ad1823c27fd344d78b22c5f8597d548adbcc46f0573e43e21e751f39446c5a5e804a12aace402b7a315d7f + languageName: node + linkType: hard + +"cliui@npm:^8.0.1": + version: 8.0.1 + resolution: "cliui@npm:8.0.1" + dependencies: + string-width: ^4.2.0 + strip-ansi: ^6.0.1 + wrap-ansi: ^7.0.0 + checksum: 79648b3b0045f2e285b76fb2e24e207c6db44323581e421c3acbd0e86454cba1b37aea976ab50195a49e7384b871e6dfb2247ad7dec53c02454ac6497394cb56 + languageName: node + linkType: hard + +"clone-deep@npm:4.0.1, clone-deep@npm:^4.0.1": + version: 4.0.1 + resolution: "clone-deep@npm:4.0.1" + dependencies: + is-plain-object: ^2.0.4 + kind-of: ^6.0.2 + shallow-clone: ^3.0.0 + checksum: 770f912fe4e6f21873c8e8fbb1e99134db3b93da32df271d00589ea4a29dbe83a9808a322c93f3bcaf8584b8b4fa6fc269fc8032efbaa6728e0c9886c74467d2 + languageName: node + linkType: hard + +"clone-response@npm:^1.0.2": + version: 1.0.3 + resolution: "clone-response@npm:1.0.3" + dependencies: + mimic-response: ^1.0.0 + checksum: 4e671cac39b11c60aa8ba0a450657194a5d6504df51bca3fac5b3bd0145c4f8e8464898f87c8406b83232e3bc5cca555f51c1f9c8ac023969ebfbf7f6bdabb2e + languageName: node + linkType: hard + +"clone@npm:^1.0.2": + version: 1.0.4 + resolution: "clone@npm:1.0.4" + checksum: d06418b7335897209e77bdd430d04f882189582e67bd1f75a04565f3f07f5b3f119a9d670c943b6697d0afb100f03b866b3b8a1f91d4d02d72c4ecf2bb64b5dd + languageName: node + linkType: hard + +"clone@npm:~2.1.2": + version: 2.1.2 + resolution: "clone@npm:2.1.2" + checksum: aaf106e9bc025b21333e2f4c12da539b568db4925c0501a1bf4070836c9e848c892fa22c35548ce0d1132b08bbbfa17a00144fe58fccdab6fa900fec4250f67d + languageName: node + linkType: hard + +"clsx@npm:^1.1.1": + version: 1.2.1 + resolution: "clsx@npm:1.2.1" + checksum: 30befca8019b2eb7dbad38cff6266cf543091dae2825c856a62a8ccf2c3ab9c2907c4d12b288b73101196767f66812365400a227581484a05f968b0307cfaf12 + languageName: node + linkType: hard + +"cmd-shim@npm:6.0.1": + version: 6.0.1 + resolution: "cmd-shim@npm:6.0.1" + checksum: 359006b3a5bb4a0ff161a44ccc18fbba947db748ef0dd12273e476792e316a5edb0945d74bfa1e91cd88ce0511025fde87901eda092c479d83cfcd6734562683 + languageName: node + linkType: hard + +"co@npm:^4.6.0": + version: 4.6.0 + resolution: "co@npm:4.6.0" + checksum: 5210d9223010eb95b29df06a91116f2cf7c8e0748a9013ed853b53f362ea0e822f1e5bb054fb3cefc645239a4cf966af1f6133a3b43f40d591f3b68ed6cf0510 + languageName: node + linkType: hard + +"collect-v8-coverage@npm:^1.0.0": + version: 1.0.1 + resolution: "collect-v8-coverage@npm:1.0.1" + checksum: 4efe0a1fccd517b65478a2364b33dadd0a43fc92a56f59aaece9b6186fe5177b2de471253587de7c91516f07c7268c2f6770b6cbcffc0e0ece353b766ec87e55 + languageName: node + linkType: hard + +"color-convert@npm:^1.9.0, color-convert@npm:^1.9.3": + version: 1.9.3 + resolution: "color-convert@npm:1.9.3" + dependencies: + color-name: 1.1.3 + checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: ~1.1.4 + checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 + languageName: node + linkType: hard + +"color-name@npm:1.1.3": + version: 1.1.3 + resolution: "color-name@npm:1.1.3" + checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d + languageName: node + linkType: hard + +"color-name@npm:^1.0.0, color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 + languageName: node + linkType: hard + +"color-string@npm:^1.6.0": + version: 1.9.1 + resolution: "color-string@npm:1.9.1" + dependencies: + color-name: ^1.0.0 + simple-swizzle: ^0.2.2 + checksum: c13fe7cff7885f603f49105827d621ce87f4571d78ba28ef4a3f1a104304748f620615e6bf065ecd2145d0d9dad83a3553f52bb25ede7239d18e9f81622f1cc5 + languageName: node + linkType: hard + +"color-support@npm:^1.1.2, color-support@npm:^1.1.3": + version: 1.1.3 + resolution: "color-support@npm:1.1.3" + bin: + color-support: bin.js + checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b + languageName: node + linkType: hard + +"color@npm:^3.2.1": + version: 3.2.1 + resolution: "color@npm:3.2.1" + dependencies: + color-convert: ^1.9.3 + color-string: ^1.6.0 + checksum: f81220e8b774d35865c2561be921f5652117638dcda7ca4029262046e37fc2444ac7bbfdd110cf1fd9c074a4ee5eda8f85944ffbdda26186b602dd9bb05f6400 + languageName: node + linkType: hard + +"colord@npm:^2.9.3": + version: 2.9.3 + resolution: "colord@npm:2.9.3" + checksum: 95d909bfbcfd8d5605cbb5af56f2d1ce2b323990258fd7c0d2eb0e6d3bb177254d7fb8213758db56bb4ede708964f78c6b992b326615f81a18a6aaf11d64c650 + languageName: node + linkType: hard + +"colorette@npm:2.0.20, colorette@npm:^2.0.14": + version: 2.0.20 + resolution: "colorette@npm:2.0.20" + checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d + languageName: node + linkType: hard + +"columnify@npm:1.6.0": + version: 1.6.0 + resolution: "columnify@npm:1.6.0" + dependencies: + strip-ansi: ^6.0.1 + wcwidth: ^1.0.0 + checksum: 0d590023616a27bcd2135c0f6ddd6fac94543263f9995538bbe391068976e30545e5534d369737ec7c3e9db4e53e70a277462de46aeb5a36e6997b4c7559c335 + languageName: node + linkType: hard + +"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: ~1.0.0 + checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c + languageName: node + linkType: hard + +"commander@npm:2, commander@npm:^2.20.0": + version: 2.20.3 + resolution: "commander@npm:2.20.3" + checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e + languageName: node + linkType: hard + +"commander@npm:7, commander@npm:^7.2.0": + version: 7.2.0 + resolution: "commander@npm:7.2.0" + checksum: 53501cbeee61d5157546c0bef0fedb6cdfc763a882136284bed9a07225f09a14b82d2a84e7637edfd1a679fb35ed9502fd58ef1d091e6287f60d790147f68ddc + languageName: node + linkType: hard + +"commander@npm:9.2.0": + version: 9.2.0 + resolution: "commander@npm:9.2.0" + checksum: 7c82e4cd969712aa6d7c055b8351807a7230f9f31ef7ec7881e11a1147511de85adf5d6ccfd200240a118eecf693b220caf6865b8efbcea558a70d35aa9ed711 + languageName: node + linkType: hard + +"commander@npm:^4.1.1": + version: 4.1.1 + resolution: "commander@npm:4.1.1" + checksum: d7b9913ff92cae20cb577a4ac6fcc121bd6223319e54a40f51a14740a681ad5c574fd29a57da478a5f234a6fa6c52cbf0b7c641353e03c648b1ae85ba670b977 + languageName: node + linkType: hard + +"commander@npm:^8.3.0": + version: 8.3.0 + resolution: "commander@npm:8.3.0" + checksum: 0f82321821fc27b83bd409510bb9deeebcfa799ff0bf5d102128b500b7af22872c0c92cb6a0ebc5a4cf19c6b550fba9cedfa7329d18c6442a625f851377bacf0 + languageName: node + linkType: hard + +"commander@npm:^9.4.1": + version: 9.5.0 + resolution: "commander@npm:9.5.0" + checksum: c7a3e27aa59e913b54a1bafd366b88650bc41d6651f0cbe258d4ff09d43d6a7394232a4dadd0bf518b3e696fdf595db1028a0d82c785b88bd61f8a440cecfade + languageName: node + linkType: hard + +"compare-func@npm:^2.0.0": + version: 2.0.0 + resolution: "compare-func@npm:2.0.0" + dependencies: + array-ify: ^1.0.0 + dot-prop: ^5.1.0 + checksum: fb71d70632baa1e93283cf9d80f30ac97f003aabee026e0b4426c9716678079ef5fea7519b84d012cbed938c476493866a38a79760564a9e21ae9433e40e6f0d + languageName: node + linkType: hard + +"compressible@npm:~2.0.16": + version: 2.0.18 + resolution: "compressible@npm:2.0.18" + dependencies: + mime-db: ">= 1.43.0 < 2" + checksum: 58321a85b375d39230405654721353f709d0c1442129e9a17081771b816302a012471a9b8f4864c7dbe02eef7f2aaac3c614795197092262e94b409c9be108f0 + languageName: node + linkType: hard + +"compression@npm:1.7.4": + version: 1.7.4 + resolution: "compression@npm:1.7.4" + dependencies: + accepts: ~1.3.5 + bytes: 3.0.0 + compressible: ~2.0.16 + debug: 2.6.9 + on-headers: ~1.0.2 + safe-buffer: 5.1.2 + vary: ~1.1.2 + checksum: 35c0f2eb1f28418978615dc1bc02075b34b1568f7f56c62d60f4214d4b7cc00d0f6d282b5f8a954f59872396bd770b6b15ffd8aa94c67d4bce9b8887b906999b + languageName: node + linkType: hard + +"compute-gcd@npm:^1.2.1": + version: 1.2.1 + resolution: "compute-gcd@npm:1.2.1" + dependencies: + validate.io-array: ^1.0.3 + validate.io-function: ^1.0.2 + validate.io-integer-array: ^1.0.0 + checksum: 51cf33b75f7c8db5142fcb99a9d84a40260993fed8e02a7ab443834186c3ab99b3fd20b30ad9075a6a9d959d69df6da74dd3be8a59c78d9f2fe780ebda8242e1 + languageName: node + linkType: hard + +"compute-lcm@npm:^1.1.2": + version: 1.1.2 + resolution: "compute-lcm@npm:1.1.2" + dependencies: + compute-gcd: ^1.2.1 + validate.io-array: ^1.0.3 + validate.io-function: ^1.0.2 + validate.io-integer-array: ^1.0.0 + checksum: d499ab57dcb48e8d0fd233b99844a06d1cc56115602c920c586e998ebba60293731f5b6976e8a1e83ae6cbfe86716f62d9432e8d94913fed8bd8352f447dc917 + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af + languageName: node + linkType: hard + +"concat-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "concat-stream@npm:2.0.0" + dependencies: + buffer-from: ^1.0.0 + inherits: ^2.0.3 + readable-stream: ^3.0.2 + typedarray: ^0.0.6 + checksum: d7f75d48f0ecd356c1545d87e22f57b488172811b1181d96021c7c4b14ab8855f5313280263dca44bb06e5222f274d047da3e290a38841ef87b59719bde967c7 + languageName: node + linkType: hard + +"console-control-strings@npm:^1.0.0, console-control-strings@npm:^1.1.0": + version: 1.1.0 + resolution: "console-control-strings@npm:1.1.0" + checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed + languageName: node + linkType: hard + +"content-disposition@npm:0.5.4": + version: 0.5.4 + resolution: "content-disposition@npm:0.5.4" + dependencies: + safe-buffer: 5.2.1 + checksum: afb9d545e296a5171d7574fcad634b2fdf698875f4006a9dd04a3e1333880c5c0c98d47b560d01216fb6505a54a2ba6a843ee3a02ec86d7e911e8315255f56c3 + languageName: node + linkType: hard + +"content-type@npm:~1.0.4, content-type@npm:~1.0.5": + version: 1.0.5 + resolution: "content-type@npm:1.0.5" + checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 + languageName: node + linkType: hard + +"conventional-changelog-angular@npm:6.0.0": + version: 6.0.0 + resolution: "conventional-changelog-angular@npm:6.0.0" + dependencies: + compare-func: ^2.0.0 + checksum: ddc59ead53a45b817d83208200967f5340866782b8362d5e2e34105fdfa3d3a31585ebbdec7750bdb9de53da869f847e8ca96634a9801f51e27ecf4e7ffe2bad + languageName: node + linkType: hard + +"conventional-changelog-core@npm:5.0.1": + version: 5.0.1 + resolution: "conventional-changelog-core@npm:5.0.1" + dependencies: + add-stream: ^1.0.0 + conventional-changelog-writer: ^6.0.0 + conventional-commits-parser: ^4.0.0 + dateformat: ^3.0.3 + get-pkg-repo: ^4.2.1 + git-raw-commits: ^3.0.0 + git-remote-origin-url: ^2.0.0 + git-semver-tags: ^5.0.0 + normalize-package-data: ^3.0.3 + read-pkg: ^3.0.0 + read-pkg-up: ^3.0.0 + checksum: 5f37f14f8d5effb4c6bf861df11e918a277ecc2cf94534eaed44d1455b11ef450d0f6d122f0e7450a44a268d9473730cf918b7558964dcba2f0ac0896824e66f + languageName: node + linkType: hard + +"conventional-changelog-preset-loader@npm:^3.0.0": + version: 3.0.0 + resolution: "conventional-changelog-preset-loader@npm:3.0.0" + checksum: 199c4730c5151f243d35c24585114900c2a7091eab5832cfeb49067a18a2b77d5c9a86b779e6e18b49278a1ff83c011c1d9bb6da95bd1f78d9e36d4d379216d5 + languageName: node + linkType: hard + +"conventional-changelog-writer@npm:^6.0.0": + version: 6.0.0 + resolution: "conventional-changelog-writer@npm:6.0.0" + dependencies: + conventional-commits-filter: ^3.0.0 + dateformat: ^3.0.3 + handlebars: ^4.7.7 + json-stringify-safe: ^5.0.1 + meow: ^8.1.2 + semver: ^6.3.0 + split: ^1.0.1 + bin: + conventional-changelog-writer: cli.js + checksum: 2515980f47d424c747f57b9e4456506a338464acd7ab50550c1dafe741bf8cb586cb85f18e1cd57d1e3b84124ae0f3e81c8e4141e3331cb4543f69ac5c6c5ea8 + languageName: node + linkType: hard + +"conventional-commits-filter@npm:^3.0.0": + version: 3.0.0 + resolution: "conventional-commits-filter@npm:3.0.0" + dependencies: + lodash.ismatch: ^4.4.0 + modify-values: ^1.0.1 + checksum: 73337f42acff7189e1dfca8d13c9448ce085ac1c09976cb33617cc909949621befb1640b1c6c30a1be4953a1be0deea9e93fa0dc86725b8be8e249a64fbb4632 + languageName: node + linkType: hard + +"conventional-commits-parser@npm:^4.0.0": + version: 4.0.0 + resolution: "conventional-commits-parser@npm:4.0.0" + dependencies: + JSONStream: ^1.3.5 + is-text-path: ^1.0.1 + meow: ^8.1.2 + split2: ^3.2.2 + bin: + conventional-commits-parser: cli.js + checksum: 12d95b5ba8e0710a6d3cd2e01f01dd7818fdf0bb2b33f4b75444e2c9aee49598776b0706a528ed49e83aec5f1896c32cbc7f8e6589f61a15187293707448f928 + languageName: node + linkType: hard + +"conventional-recommended-bump@npm:7.0.1": + version: 7.0.1 + resolution: "conventional-recommended-bump@npm:7.0.1" + dependencies: + concat-stream: ^2.0.0 + conventional-changelog-preset-loader: ^3.0.0 + conventional-commits-filter: ^3.0.0 + conventional-commits-parser: ^4.0.0 + git-raw-commits: ^3.0.0 + git-semver-tags: ^5.0.0 + meow: ^8.1.2 + bin: + conventional-recommended-bump: cli.js + checksum: e2d1f2f40f93612a6da035d0c1a12d70208e0da509a17a9c9296a05e73a6eca5d81fe8c6a7b45e973181fa7c876c6edb9a114a2d7da4f6df00c47c7684ab62d2 + languageName: node + linkType: hard + +"convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": + version: 1.9.0 + resolution: "convert-source-map@npm:1.9.0" + checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 + languageName: node + linkType: hard + +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 63ae9933be5a2b8d4509daca5124e20c14d023c820258e484e32dc324d34c2754e71297c94a05784064ad27615037ef677e3f0c00469fb55f409d2bb21261035 + languageName: node + linkType: hard + +"cookie-signature@npm:1.0.6": + version: 1.0.6 + resolution: "cookie-signature@npm:1.0.6" + checksum: f4e1b0a98a27a0e6e66fd7ea4e4e9d8e038f624058371bf4499cfcd8f3980be9a121486995202ba3fca74fbed93a407d6d54d43a43f96fd28d0bd7a06761591a + languageName: node + linkType: hard + +"cookie@npm:0.5.0": + version: 0.5.0 + resolution: "cookie@npm:0.5.0" + checksum: 1f4bd2ca5765f8c9689a7e8954183f5332139eb72b6ff783d8947032ec1fdf43109852c178e21a953a30c0dd42257828185be01b49d1eb1a67fd054ca588a180 + languageName: node + linkType: hard + +"cookies@npm:0.8.0": + version: 0.8.0 + resolution: "cookies@npm:0.8.0" + dependencies: + depd: ~2.0.0 + keygrip: ~1.1.0 + checksum: 806055a44f128705265b1bc6a853058da18bf80dea3654ad99be20985b1fa1b14f86c1eef73644aab8071241f8a78acd57202b54c4c5c70769fc694fbb9c4edc + languageName: node + linkType: hard + +"copy-webpack-plugin@npm:^11.0.0": + version: 11.0.0 + resolution: "copy-webpack-plugin@npm:11.0.0" + dependencies: + fast-glob: ^3.2.11 + glob-parent: ^6.0.1 + globby: ^13.1.1 + normalize-path: ^3.0.0 + schema-utils: ^4.0.0 + serialize-javascript: ^6.0.0 + peerDependencies: + webpack: ^5.1.0 + checksum: df4f8743f003a29ee7dd3d9b1789998a3a99051c92afb2ba2203d3dacfa696f4e757b275560fafb8f206e520a0aa78af34b990324a0e36c2326cefdeef3ca82e + languageName: node + linkType: hard + +"core-js-compat@npm:^3.25.1": + version: 3.29.0 + resolution: "core-js-compat@npm:3.29.0" + dependencies: + browserslist: ^4.21.5 + checksum: ca5d370296c15ebd5f961dae6b6a24a153a84937bff58543099b7f1c407e8d5bbafafa7ca27e65baad522ece762d6356e1d6ea9efa99815f6fefd150fac7e8a5 + languageName: node + linkType: hard + +"core-js@npm:3.30.2": + version: 3.30.2 + resolution: "core-js@npm:3.30.2" + checksum: 73d47e2b9d9f502800973982d08e995bbf04832e20b04e04be31dd7607247158271315e9328788a2408190e291c7ffbefad141167b1e57dea9f983e1e723541e + languageName: node + linkType: hard + +"core-util-is@npm:1.0.2, core-util-is@npm:~1.0.0": + version: 1.0.2 + resolution: "core-util-is@npm:1.0.2" + checksum: 7a4c925b497a2c91421e25bf76d6d8190f0b2359a9200dbeed136e63b2931d6294d3b1893eda378883ed363cd950f44a12a401384c609839ea616befb7927dab + languageName: node + linkType: hard + +"cors@npm:2.8.5": + version: 2.8.5 + resolution: "cors@npm:2.8.5" + dependencies: + object-assign: ^4 + vary: ^1 + checksum: ced838404ccd184f61ab4fdc5847035b681c90db7ac17e428f3d81d69e2989d2b680cc254da0e2554f5ed4f8a341820a1ce3d1c16b499f6e2f47a1b9b07b5006 + languageName: node + linkType: hard + +"cosmiconfig@npm:^8.2.0": + version: 8.2.0 + resolution: "cosmiconfig@npm:8.2.0" + dependencies: + import-fresh: ^3.2.1 + js-yaml: ^4.1.0 + parse-json: ^5.0.0 + path-type: ^4.0.0 + checksum: 836d5d8efa750f3fb17b03d6ca74cd3154ed025dffd045304b3ef59637f662bde1e5dc88f8830080d180ec60841719cf4ea2ce73fb21ec694b16865c478ff297 + languageName: node + linkType: hard + +"crelt@npm:^1.0.5": + version: 1.0.5 + resolution: "crelt@npm:1.0.5" + checksum: 04a618c5878e12a14a9a328a49ff6e37bed76abb88b72e661c56b5f161d8a9aca133650da6bcbc5224ad1f7f43a69325627f209e92a21002986d52a8f844b367 + languageName: node + linkType: hard + +"cross-spawn@npm:7.0.3, cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": + version: 7.0.3 + resolution: "cross-spawn@npm:7.0.3" + dependencies: + path-key: ^3.1.0 + shebang-command: ^2.0.0 + which: ^2.0.1 + checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 + languageName: node + linkType: hard + +"crypto@npm:~1.0.1": + version: 1.0.1 + resolution: "crypto@npm:1.0.1" + checksum: 087fe3165bd94c333a49e6ed66a0193911f63eac38a24f379b3001a5fe260a59c413646e53a0f67875ba13902b2686d81dc703cb2c147a4ec727dcdc04e5645e + languageName: node + linkType: hard + +"css-functions-list@npm:^3.1.0": + version: 3.1.0 + resolution: "css-functions-list@npm:3.1.0" + checksum: 8a7c9d4ae57cb2f01500263e65a21372048d359ca7aa6430a32a736fe2a421decfebe45e579124b9a158ec68aba2eadcd733e568495a7698240d9607d31f681b + languageName: node + linkType: hard + +"css-loader@npm:^6.7.1": + version: 6.7.3 + resolution: "css-loader@npm:6.7.3" + dependencies: + icss-utils: ^5.1.0 + postcss: ^8.4.19 + postcss-modules-extract-imports: ^3.0.0 + postcss-modules-local-by-default: ^4.0.0 + postcss-modules-scope: ^3.0.0 + postcss-modules-values: ^4.0.0 + postcss-value-parser: ^4.2.0 + semver: ^7.3.8 + peerDependencies: + webpack: ^5.0.0 + checksum: 473cc32b6c837c2848e2051ad1ba331c1457449f47442e75a8c480d9891451434ada241f7e3de2347e57de17fcd84610b3bcfc4a9da41102cdaedd1e17902d31 + languageName: node + linkType: hard + +"css-select@npm:^4.1.3": + version: 4.3.0 + resolution: "css-select@npm:4.3.0" + dependencies: + boolbase: ^1.0.0 + css-what: ^6.0.1 + domhandler: ^4.3.1 + domutils: ^2.8.0 + nth-check: ^2.0.1 + checksum: d6202736839194dd7f910320032e7cfc40372f025e4bf21ca5bf6eb0a33264f322f50ba9c0adc35dadd342d3d6fae5ca244779a4873afbfa76561e343f2058e0 + languageName: node + linkType: hard + +"css-select@npm:^5.1.0": + version: 5.1.0 + resolution: "css-select@npm:5.1.0" + dependencies: + boolbase: ^1.0.0 + css-what: ^6.1.0 + domhandler: ^5.0.2 + domutils: ^3.0.1 + nth-check: ^2.0.1 + checksum: 2772c049b188d3b8a8159907192e926e11824aea525b8282981f72ba3f349cf9ecd523fdf7734875ee2cb772246c22117fc062da105b6d59afe8dcd5c99c9bda + languageName: node + linkType: hard + +"css-tree@npm:^2.2.1, css-tree@npm:^2.3.1": + version: 2.3.1 + resolution: "css-tree@npm:2.3.1" + dependencies: + mdn-data: 2.0.30 + source-map-js: ^1.0.1 + checksum: 493cc24b5c22b05ee5314b8a0d72d8a5869491c1458017ae5ed75aeb6c3596637dbe1b11dac2548974624adec9f7a1f3a6cf40593dc1f9185eb0e8279543fbc0 + languageName: node + linkType: hard + +"css-tree@npm:~2.2.0": + version: 2.2.1 + resolution: "css-tree@npm:2.2.1" + dependencies: + mdn-data: 2.0.28 + source-map-js: ^1.0.1 + checksum: b94aa8cc2f09e6f66c91548411fcf74badcbad3e150345074715012d16333ce573596ff5dfca03c2a87edf1924716db765120f94247e919d72753628ba3aba27 + languageName: node + linkType: hard + +"css-what@npm:^6.0.1, css-what@npm:^6.1.0": + version: 6.1.0 + resolution: "css-what@npm:6.1.0" + checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe + languageName: node + linkType: hard + +"cssesc@npm:^3.0.0": + version: 3.0.0 + resolution: "cssesc@npm:3.0.0" + bin: + cssesc: bin/cssesc + checksum: f8c4ababffbc5e2ddf2fa9957dda1ee4af6048e22aeda1869d0d00843223c1b13ad3f5d88b51caa46c994225eacb636b764eb807a8883e2fb6f99b4f4e8c48b2 + languageName: node + linkType: hard + +"csso@npm:^5.0.5": + version: 5.0.5 + resolution: "csso@npm:5.0.5" + dependencies: + css-tree: ~2.2.0 + checksum: 0ad858d36bf5012ed243e9ec69962a867509061986d2ee07cc040a4b26e4d062c00d4c07e5ba8d430706ceb02dd87edd30a52b5937fd45b1b6f2119c4993d59a + languageName: node + linkType: hard + +"cssom@npm:^0.5.0": + version: 0.5.0 + resolution: "cssom@npm:0.5.0" + checksum: 823471aa30091c59e0a305927c30e7768939b6af70405808f8d2ce1ca778cddcb24722717392438329d1691f9a87cb0183b64b8d779b56a961546d54854fde01 + languageName: node + linkType: hard + +"cssom@npm:~0.3.6": + version: 0.3.8 + resolution: "cssom@npm:0.3.8" + checksum: 24beb3087c76c0d52dd458be9ee1fbc80ac771478a9baef35dd258cdeb527c68eb43204dd439692bb2b1ae5272fa5f2946d10946edab0d04f1078f85e06bc7f6 + languageName: node + linkType: hard + +"cssstyle@npm:^2.3.0": + version: 2.3.0 + resolution: "cssstyle@npm:2.3.0" + dependencies: + cssom: ~0.3.6 + checksum: 5f05e6fd2e3df0b44695c2f08b9ef38b011862b274e320665176467c0725e44a53e341bc4959a41176e83b66064ab786262e7380fd1cabeae6efee0d255bb4e3 + languageName: node + linkType: hard + +"csstype@npm:3.0.10, csstype@npm:^3.0.10, csstype@npm:^3.0.2": + version: 3.0.10 + resolution: "csstype@npm:3.0.10" + checksum: 20a8fa324f2b33ddf94aa7507d1b6ab3daa6f3cc308888dc50126585d7952f2471de69b2dbe0635d1fdc31223fef8e070842691877e725caf456e2378685a631 + languageName: node + linkType: hard + +"csv-spectrum@npm:^1.0.0": + version: 1.0.0 + resolution: "csv-spectrum@npm:1.0.0" + checksum: e93fa36350f486a3ac10ad064e53821256984cec1bf08fd742301661bbeb28fb5d2943f0e996156a4a07e5f2955141377f08a6256342e90e588155a0fd93f0ab + languageName: node + linkType: hard + +"d3-array@npm:1 - 3, d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:2.5.0 - 3, d3-array@npm:3.2.2, d3-array@npm:^3.2.2": + version: 3.2.2 + resolution: "d3-array@npm:3.2.2" + dependencies: + internmap: 1 - 2 + checksum: 98af3db792685ceca5d9c3721efba0c567520da5532b2c7a590fd83627a598ea225d11c2cecbad404dc154120feb5ea6df0ded38f82ddf342c714cfd0c6143d1 + languageName: node + linkType: hard + +"d3-color@npm:1 - 3, d3-color@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-color@npm:3.1.0" + checksum: 4931fbfda5d7c4b5cfa283a13c91a954f86e3b69d75ce588d06cde6c3628cebfc3af2069ccf225e982e8987c612aa7948b3932163ce15eb3c11cd7c003f3ee3b + languageName: node + linkType: hard + +"d3-delaunay@npm:^6.0.2": + version: 6.0.2 + resolution: "d3-delaunay@npm:6.0.2" + dependencies: + delaunator: 5 + checksum: 80b18686dd7a5919a570000061f1515d106b7c7e3cba9da55706c312fc8f6de58a72674f2ea4eadc6694611f2df59f82c8b9d304845dd8b7903ee1f303aa5865 + languageName: node + linkType: hard + +"d3-dispatch@npm:1 - 3": + version: 3.0.1 + resolution: "d3-dispatch@npm:3.0.1" + checksum: fdfd4a230f46463e28e5b22a45dd76d03be9345b605e1b5dc7d18bd7ebf504e6c00ae123fd6d03e23d9e2711e01f0e14ea89cd0632545b9f0c00b924ba4be223 + languageName: node + linkType: hard + +"d3-dsv@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-dsv@npm:3.0.1" + dependencies: + commander: 7 + iconv-lite: 0.6 + rw: 1 + bin: + csv2json: bin/dsv2json.js + csv2tsv: bin/dsv2dsv.js + dsv2dsv: bin/dsv2dsv.js + dsv2json: bin/dsv2json.js + json2csv: bin/json2dsv.js + json2dsv: bin/json2dsv.js + json2tsv: bin/json2dsv.js + tsv2csv: bin/dsv2dsv.js + tsv2json: bin/dsv2json.js + checksum: 5fc0723647269d5dccd181d74f2265920ab368a2868b0b4f55ffa2fecdfb7814390ea28622cd61ee5d9594ab262879509059544e9f815c54fe76fbfb4ffa4c8a + languageName: node + linkType: hard + +"d3-force@npm:^3.0.0": + version: 3.0.0 + resolution: "d3-force@npm:3.0.0" + dependencies: + d3-dispatch: 1 - 3 + d3-quadtree: 1 - 3 + d3-timer: 1 - 3 + checksum: 6c7e96438cab62fa32aeadb0ade3297b62b51f81b1b38b0a60a5ec9fd627d74090c1189654d92df2250775f31b06812342f089f1d5947de9960a635ee3581def + languageName: node + linkType: hard + +"d3-format@npm:1 - 3, d3-format@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-format@npm:3.1.0" + checksum: f345ec3b8ad3cab19bff5dead395bd9f5590628eb97a389b1dd89f0b204c7c4fc1d9520f13231c2c7cf14b7c9a8cf10f8ef15bde2befbab41454a569bd706ca2 + languageName: node + linkType: hard + +"d3-geo-projection@npm:^4.0.0": + version: 4.0.0 + resolution: "d3-geo-projection@npm:4.0.0" + dependencies: + commander: 7 + d3-array: 1 - 3 + d3-geo: 1.12.0 - 3 + bin: + geo2svg: bin/geo2svg.js + geograticule: bin/geograticule.js + geoproject: bin/geoproject.js + geoquantize: bin/geoquantize.js + geostitch: bin/geostitch.js + checksum: 631422b10dd78d1047ba5a3b073148bea27721060bd7087a5fa6c053ca80445d26432e505e0e3acbd6e0d76cf577c61bf9a5db70dabbc9310c493de1f7ff736d + languageName: node + linkType: hard + +"d3-geo@npm:1.12.0 - 3, d3-geo@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-geo@npm:3.1.0" + dependencies: + d3-array: 2.5.0 - 3 + checksum: adf82b0c105c0c5951ae0a833d4dfc479a563791ad7938579fa14e1cffd623b469d8aa7a37dc413a327fb6ac56880f3da3f6c43d4abe3c923972dd98f34f37d1 + languageName: node + linkType: hard + +"d3-hierarchy@npm:^3.1.2": + version: 3.1.2 + resolution: "d3-hierarchy@npm:3.1.2" + checksum: 0fd946a8c5fd4686d43d3e11bbfc2037a145fda29d2261ccd0e36f70b66af6d7638e2c0c7112124d63fc3d3127197a00a6aecf676bd5bd392a94d7235a214263 + languageName: node + linkType: hard + +"d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-interpolate@npm:3.0.1" + dependencies: + d3-color: 1 - 3 + checksum: a42ba314e295e95e5365eff0f604834e67e4a3b3c7102458781c477bd67e9b24b6bb9d8e41ff5521050a3f2c7c0c4bbbb6e187fd586daa3980943095b267e78b + languageName: node + linkType: hard + +"d3-path@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-path@npm:3.1.0" + checksum: 2306f1bd9191e1eac895ec13e3064f732a85f243d6e627d242a313f9777756838a2215ea11562f0c7630c7c3b16a19ec1fe0948b1c82f3317fac55882f6ee5d8 + languageName: node + linkType: hard + +"d3-quadtree@npm:1 - 3": + version: 3.0.1 + resolution: "d3-quadtree@npm:3.0.1" + checksum: 5469d462763811475f34a7294d984f3eb100515b0585ca5b249656f6b1a6e99b20056a2d2e463cc9944b888896d2b1d07859c50f9c0cf23438df9cd2e3146066 + languageName: node + linkType: hard + +"d3-scale@npm:^4.0.2": + version: 4.0.2 + resolution: "d3-scale@npm:4.0.2" + dependencies: + d3-array: 2.10.0 - 3 + d3-format: 1 - 3 + d3-interpolate: 1.2.0 - 3 + d3-time: 2.1.1 - 3 + d3-time-format: 2 - 4 + checksum: a9c770d283162c3bd11477c3d9d485d07f8db2071665f1a4ad23eec3e515e2cefbd369059ec677c9ac849877d1a765494e90e92051d4f21111aa56791c98729e + languageName: node + linkType: hard + +"d3-shape@npm:^3.2.0": + version: 3.2.0 + resolution: "d3-shape@npm:3.2.0" + dependencies: + d3-path: ^3.1.0 + checksum: de2af5fc9a93036a7b68581ca0bfc4aca2d5a328aa7ba7064c11aedd44d24f310c20c40157cb654359d4c15c3ef369f95ee53d71221017276e34172c7b719cfa + languageName: node + linkType: hard + +"d3-time-format@npm:2 - 4, d3-time-format@npm:^4.1.0": + version: 4.1.0 + resolution: "d3-time-format@npm:4.1.0" + dependencies: + d3-time: 1 - 3 + checksum: 7342bce28355378152bbd4db4e275405439cabba082d9cd01946d40581140481c8328456d91740b0fe513c51ec4a467f4471ffa390c7e0e30ea30e9ec98fcdf4 + languageName: node + linkType: hard + +"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-time@npm:3.1.0" + dependencies: + d3-array: 2 - 3 + checksum: 613b435352a78d9f31b7f68540788186d8c331b63feca60ad21c88e9db1989fe888f97f242322ebd6365e45ec3fb206a4324cd4ca0dfffa1d9b5feb856ba00a7 + languageName: node + linkType: hard + +"d3-timer@npm:1 - 3, d3-timer@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-timer@npm:3.0.1" + checksum: 1cfddf86d7bca22f73f2c427f52dfa35c49f50d64e187eb788dcad6e927625c636aa18ae4edd44d084eb9d1f81d8ca4ec305dae7f733c15846a824575b789d73 + languageName: node + linkType: hard + +"d@npm:1, d@npm:^1.0.1": + version: 1.0.1 + resolution: "d@npm:1.0.1" + dependencies: + es5-ext: ^0.10.50 + type: ^1.0.1 + checksum: 49ca0639c7b822db670de93d4fbce44b4aa072cd848c76292c9978a8cd0fff1028763020ff4b0f147bd77bfe29b4c7f82e0f71ade76b2a06100543cdfd948d19 + languageName: node + linkType: hard + +"dargs@npm:^7.0.0": + version: 7.0.0 + resolution: "dargs@npm:7.0.0" + checksum: b8f1e3cba59c42e1f13a114ad4848c3fc1cf7470f633ee9e9f1043762429bc97d91ae31b826fb135eefde203a3fdb20deb0c0a0222ac29d937b8046085d668d1 + languageName: node + linkType: hard + +"dashdash@npm:^1.12.0": + version: 1.14.1 + resolution: "dashdash@npm:1.14.1" + dependencies: + assert-plus: ^1.0.0 + checksum: 3634c249570f7f34e3d34f866c93f866c5b417f0dd616275decae08147dcdf8fccfaa5947380ccfb0473998ea3a8057c0b4cd90c875740ee685d0624b2983598 + languageName: node + linkType: hard + +"data-urls@npm:^2.0.0": + version: 2.0.0 + resolution: "data-urls@npm:2.0.0" + dependencies: + abab: ^2.0.3 + whatwg-mimetype: ^2.3.0 + whatwg-url: ^8.0.0 + checksum: 97caf828aac25e25e04ba6869db0f99c75e6859bb5b424ada28d3e7841941ebf08ddff3c1b1bb4585986bd507a5d54c2a716853ea6cb98af877400e637393e71 + languageName: node + linkType: hard + +"data-urls@npm:^3.0.2": + version: 3.0.2 + resolution: "data-urls@npm:3.0.2" + dependencies: + abab: ^2.0.6 + whatwg-mimetype: ^3.0.0 + whatwg-url: ^11.0.0 + checksum: 033fc3dd0fba6d24bc9a024ddcf9923691dd24f90a3d26f6545d6a2f71ec6956f93462f2cdf2183cc46f10dc01ed3bcb36731a8208456eb1a08147e571fe2a76 + languageName: node + linkType: hard + +"dateformat@npm:^3.0.3": + version: 3.0.3 + resolution: "dateformat@npm:3.0.3" + checksum: ca4911148abb09887bd9bdcd632c399b06f3ecad709a18eb594d289a1031982f441e08e281db77ffebcb2cbcbfa1ac578a7cbfbf8743f41009aa5adc1846ed34 + languageName: node + linkType: hard + +"dayjs@npm:1.11.7": + version: 1.11.7 + resolution: "dayjs@npm:1.11.7" + checksum: 5003a7c1dd9ed51385beb658231c3548700b82d3548c0cfbe549d85f2d08e90e972510282b7506941452c58d32136d6362f009c77ca55381a09c704e9f177ebb + languageName: node + linkType: hard + +"debug@npm:2.6.9, debug@npm:^2.6.9": + version: 2.6.9 + resolution: "debug@npm:2.6.9" + dependencies: + ms: 2.0.0 + checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": + version: 4.3.4 + resolution: "debug@npm:4.3.4" + dependencies: + ms: 2.1.2 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + languageName: node + linkType: hard + +"decamelize-keys@npm:^1.1.0": + version: 1.1.1 + resolution: "decamelize-keys@npm:1.1.1" + dependencies: + decamelize: ^1.1.0 + map-obj: ^1.0.0 + checksum: fc645fe20b7bda2680bbf9481a3477257a7f9304b1691036092b97ab04c0ab53e3bf9fcc2d2ae382536568e402ec41fb11e1d4c3836a9abe2d813dd9ef4311e0 + languageName: node + linkType: hard + +"decamelize@npm:^1.1.0": + version: 1.2.0 + resolution: "decamelize@npm:1.2.0" + checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa + languageName: node + linkType: hard + +"decamelize@npm:^5.0.0": + version: 5.0.1 + resolution: "decamelize@npm:5.0.1" + checksum: 7c3b1ed4b3e60e7fbc00a35fb248298527c1cdfe603e41dfcf05e6c4a8cb9efbee60630deb677ed428908fb4e74e322966c687a094d1478ddc9c3a74e9dc7140 + languageName: node + linkType: hard + +"decimal.js@npm:^10.4.2": + version: 10.4.3 + resolution: "decimal.js@npm:10.4.3" + checksum: 796404dcfa9d1dbfdc48870229d57f788b48c21c603c3f6554a1c17c10195fc1024de338b0cf9e1efe0c7c167eeb18f04548979bcc5fdfabebb7cc0ae3287bae + languageName: node + linkType: hard + +"decompress-response@npm:^4.2.0": + version: 4.2.1 + resolution: "decompress-response@npm:4.2.1" + dependencies: + mimic-response: ^2.0.0 + checksum: 4e783ca4dfe9417354d61349750fe05236f565a4415a6ca20983a311be2371debaedd9104c0b0e7b36e5f167aeaae04f84f1a0b3f8be4162f1d7d15598b8fdba + languageName: node + linkType: hard + +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: ^3.1.0 + checksum: d377cf47e02d805e283866c3f50d3d21578b779731e8c5072d6ce8c13cc31493db1c2f6784da9d1d5250822120cefa44f1deab112d5981015f2e17444b763812 + languageName: node + linkType: hard + +"dedent@npm:0.7.0, dedent@npm:^0.7.0": + version: 0.7.0 + resolution: "dedent@npm:0.7.0" + checksum: 87de191050d9a40dd70cad01159a0bcf05ecb59750951242070b6abf9569088684880d00ba92a955b4058804f16eeaf91d604f283929b4f614d181cd7ae633d2 + languageName: node + linkType: hard + +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 7be7e5a8d468d6b10e6a67c3de828f55001b6eb515d014f7aeb9066ce36bd5717161eb47d6a0f7bed8a9083935b465bc163ee2581c8b128d29bf61092fdf57a7 + languageName: node + linkType: hard + +"deep-is@npm:^0.1.3, deep-is@npm:~0.1.3": + version: 0.1.4 + resolution: "deep-is@npm:0.1.4" + checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 + languageName: node + linkType: hard + +"deepmerge@npm:^4.2.2": + version: 4.3.0 + resolution: "deepmerge@npm:4.3.0" + checksum: c7980eb5c5be040b371f1df0d566473875cfabed9f672ccc177b81ba8eee5686ce2478de2f1d0076391621cbe729e5eacda397179a59ef0f68901849647db126 + languageName: node + linkType: hard + +"default-browser-id@npm:^3.0.0": + version: 3.0.0 + resolution: "default-browser-id@npm:3.0.0" + dependencies: + bplist-parser: ^0.2.0 + untildify: ^4.0.0 + checksum: 279c7ad492542e5556336b6c254a4eaf31b2c63a5433265655ae6e47301197b6cfb15c595a6fdc6463b2ff8e1a1a1ed3cba56038a60e1527ba4ab1628c6b9941 + languageName: node + linkType: hard + +"default-browser@npm:^4.0.0": + version: 4.0.0 + resolution: "default-browser@npm:4.0.0" + dependencies: + bundle-name: ^3.0.0 + default-browser-id: ^3.0.0 + execa: ^7.1.1 + titleize: ^3.0.0 + checksum: 40c5af984799042b140300be5639c9742599bda76dc9eba5ac9ad5943c83dd36cebc4471eafcfddf8e0ec817166d5ba89d56f08e66a126c7c7908a179cead1a7 + languageName: node + linkType: hard + +"defaults@npm:^1.0.3": + version: 1.0.4 + resolution: "defaults@npm:1.0.4" + dependencies: + clone: ^1.0.2 + checksum: 3a88b7a587fc076b84e60affad8b85245c01f60f38fc1d259e7ac1d89eb9ce6abb19e27215de46b98568dd5bc48471730b327637e6f20b0f1bc85cf00440c80a + languageName: node + linkType: hard + +"defer-to-connect@npm:^2.0.0": + version: 2.0.1 + resolution: "defer-to-connect@npm:2.0.1" + checksum: 8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b + languageName: node + linkType: hard + +"define-lazy-prop@npm:^2.0.0": + version: 2.0.0 + resolution: "define-lazy-prop@npm:2.0.0" + checksum: 0115fdb065e0490918ba271d7339c42453d209d4cb619dfe635870d906731eff3e1ade8028bb461ea27ce8264ec5e22c6980612d332895977e89c1bbc80fcee2 + languageName: node + linkType: hard + +"define-lazy-prop@npm:^3.0.0": + version: 3.0.0 + resolution: "define-lazy-prop@npm:3.0.0" + checksum: 54884f94caac0791bf6395a3ec530ce901cf71c47b0196b8754f3fd17edb6c0e80149c1214429d851873bb0d689dbe08dcedbb2306dc45c8534a5934723851b6 + languageName: node + linkType: hard + +"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4": + version: 1.2.0 + resolution: "define-properties@npm:1.2.0" + dependencies: + has-property-descriptors: ^1.0.0 + object-keys: ^1.1.1 + checksum: e60aee6a19b102df4e2b1f301816804e81ab48bb91f00d0d935f269bf4b3f79c88b39e4f89eaa132890d23267335fd1140dfcd8d5ccd61031a0a2c41a54e33a6 + languageName: node + linkType: hard + +"delaunator@npm:5": + version: 5.0.0 + resolution: "delaunator@npm:5.0.0" + dependencies: + robust-predicates: ^3.0.0 + checksum: d6764188442b7f7c6bcacebd96edc00e35f542a96f1af3ef600e586bfb9849a3682c489c0ab423440c90bc4c7cac77f28761babff76fa29e193e1cf50a95b860 + languageName: node + linkType: hard + +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 + languageName: node + linkType: hard + +"delegates@npm:^1.0.0": + version: 1.0.0 + resolution: "delegates@npm:1.0.0" + checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd + languageName: node + linkType: hard + +"depd@npm:2.0.0, depd@npm:^2.0.0, depd@npm:~2.0.0": + version: 2.0.0 + resolution: "depd@npm:2.0.0" + checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a + languageName: node + linkType: hard + +"dependency-graph@npm:^0.11.0": + version: 0.11.0 + resolution: "dependency-graph@npm:0.11.0" + checksum: 477204beaa9be69e642bc31ffe7a8c383d0cf48fa27acbc91c5df01431ab913e65c154213d2ef83d034c98d77280743ec85e5da018a97a18dd43d3c0b78b28cd + languageName: node + linkType: hard + +"deprecation@npm:^2.0.0": + version: 2.3.1 + resolution: "deprecation@npm:2.3.1" + checksum: f56a05e182c2c195071385455956b0c4106fe14e36245b00c689ceef8e8ab639235176a96977ba7c74afb173317fac2e0ec6ec7a1c6d1e6eaa401c586c714132 + languageName: node + linkType: hard + +"destroy@npm:1.2.0": + version: 1.2.0 + resolution: "destroy@npm:1.2.0" + checksum: 0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 + languageName: node + linkType: hard + +"detect-indent@npm:^5.0.0": + version: 5.0.0 + resolution: "detect-indent@npm:5.0.0" + checksum: 61763211daa498e00eec073aba95d544ae5baed19286a0a655697fa4fffc9f4539c8376e2c7df8fa11d6f8eaa16c1e6a689f403ac41ee78a060278cdadefe2ff + languageName: node + linkType: hard + +"detect-indent@npm:^6.0.0": + version: 6.1.0 + resolution: "detect-indent@npm:6.1.0" + checksum: ab953a73c72dbd4e8fc68e4ed4bfd92c97eb6c43734af3900add963fd3a9316f3bc0578b018b24198d4c31a358571eff5f0656e81a1f3b9ad5c547d58b2d093d + languageName: node + linkType: hard + +"detect-libc@npm:^2.0.0": + version: 2.0.1 + resolution: "detect-libc@npm:2.0.1" + checksum: ccb05fcabbb555beb544d48080179c18523a343face9ee4e1a86605a8715b4169f94d663c21a03c310ac824592f2ba9a5270218819bb411ad7be578a527593d7 + languageName: node + linkType: hard + +"detect-newline@npm:3.1.0, detect-newline@npm:^3.0.0": + version: 3.1.0 + resolution: "detect-newline@npm:3.1.0" + checksum: ae6cd429c41ad01b164c59ea36f264a2c479598e61cba7c99da24175a7ab80ddf066420f2bec9a1c57a6bead411b4655ff15ad7d281c000a89791f48cbe939e7 + languageName: node + linkType: hard + +"diff-sequences@npm:^29.4.3": + version: 29.4.3 + resolution: "diff-sequences@npm:29.4.3" + checksum: 28b265e04fdddcf7f9f814effe102cc95a9dec0564a579b5aed140edb24fc345c611ca52d76d725a3cab55d3888b915b5e8a4702e0f6058968a90fa5f41fcde7 + languageName: node + linkType: hard + +"diff@npm:^5.1.0": + version: 5.1.0 + resolution: "diff@npm:5.1.0" + checksum: c7bf0df7c9bfbe1cf8a678fd1b2137c4fb11be117a67bc18a0e03ae75105e8533dbfb1cda6b46beb3586ef5aed22143ef9d70713977d5fb1f9114e21455fba90 + languageName: node + linkType: hard + +"dir-glob@npm:^3.0.1": + version: 3.0.1 + resolution: "dir-glob@npm:3.0.1" + dependencies: + path-type: ^4.0.0 + checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 + languageName: node + linkType: hard + +"doctrine@npm:^2.1.0": + version: 2.1.0 + resolution: "doctrine@npm:2.1.0" + dependencies: + esutils: ^2.0.2 + checksum: a45e277f7feaed309fe658ace1ff286c6e2002ac515af0aaf37145b8baa96e49899638c7cd47dccf84c3d32abfc113246625b3ac8f552d1046072adee13b0dc8 + languageName: node + linkType: hard + +"doctrine@npm:^3.0.0": + version: 3.0.0 + resolution: "doctrine@npm:3.0.0" + dependencies: + esutils: ^2.0.2 + checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce + languageName: node + linkType: hard + +"dom-converter@npm:^0.2.0": + version: 0.2.0 + resolution: "dom-converter@npm:0.2.0" + dependencies: + utila: ~0.4 + checksum: ea52fe303f5392e48dea563abef0e6fb3a478b8dbe3c599e99bb5d53981c6c38fc4944e56bb92a8ead6bb989d10b7914722ae11febbd2fd0910e33b9fc4aaa77 + languageName: node + linkType: hard + +"dom-serializer@npm:^1.0.1": + version: 1.4.1 + resolution: "dom-serializer@npm:1.4.1" + dependencies: + domelementtype: ^2.0.1 + domhandler: ^4.2.0 + entities: ^2.0.0 + checksum: fbb0b01f87a8a2d18e6e5a388ad0f7ec4a5c05c06d219377da1abc7bb0f674d804f4a8a94e3f71ff15f6cb7dcfc75704a54b261db672b9b3ab03da6b758b0b22 + languageName: node + linkType: hard + +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.2 + entities: ^4.2.0 + checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 + languageName: node + linkType: hard + +"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 + languageName: node + linkType: hard + +"domexception@npm:^4.0.0": + version: 4.0.0 + resolution: "domexception@npm:4.0.0" + dependencies: + webidl-conversions: ^7.0.0 + checksum: ddbc1268edf33a8ba02ccc596735ede80375ee0cf124b30d2f05df5b464ba78ef4f49889b6391df4a04954e63d42d5631c7fcf8b1c4f12bc531252977a5f13d5 + languageName: node + linkType: hard + +"domhandler@npm:^3.0.0": + version: 3.3.0 + resolution: "domhandler@npm:3.3.0" + dependencies: + domelementtype: ^2.0.1 + checksum: 850e5e9fee7834ab4314811e18bc1f4294d7eafbf6a79ad03cbe50cf964108935c97257ac248944d72a9312b4a18dfa8323e857d23278964dc83b1f124467fa3 + languageName: node + linkType: hard + +"domhandler@npm:^4.0.0, domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": + version: 4.3.1 + resolution: "domhandler@npm:4.3.1" + dependencies: + domelementtype: ^2.2.0 + checksum: 4c665ceed016e1911bf7d1dadc09dc888090b64dee7851cccd2fcf5442747ec39c647bb1cb8c8919f8bbdd0f0c625a6bafeeed4b2d656bbecdbae893f43ffaaa + languageName: node + linkType: hard + +"domhandler@npm:^5.0.1, domhandler@npm:^5.0.2": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: ^2.3.0 + checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c + languageName: node + linkType: hard + +"domutils@npm:^2.0.0, domutils@npm:^2.5.2, domutils@npm:^2.8.0": + version: 2.8.0 + resolution: "domutils@npm:2.8.0" + dependencies: + dom-serializer: ^1.0.1 + domelementtype: ^2.2.0 + domhandler: ^4.2.0 + checksum: abf7434315283e9aadc2a24bac0e00eab07ae4313b40cc239f89d84d7315ebdfd2fb1b5bf750a96bc1b4403d7237c7b2ebf60459be394d625ead4ca89b934391 + languageName: node + linkType: hard + +"domutils@npm:^3.0.1": + version: 3.0.1 + resolution: "domutils@npm:3.0.1" + dependencies: + dom-serializer: ^2.0.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.1 + checksum: 23aa7a840572d395220e173cb6263b0d028596e3950100520870a125af33ff819e6f609e1606d6f7d73bd9e7feb03bb404286e57a39063b5384c62b724d987b3 + languageName: node + linkType: hard + +"dot-case@npm:^3.0.4": + version: 3.0.4 + resolution: "dot-case@npm:3.0.4" + dependencies: + no-case: ^3.0.4 + tslib: ^2.0.3 + checksum: a65e3519414856df0228b9f645332f974f2bf5433370f544a681122eab59e66038fc3349b4be1cdc47152779dac71a5864f1ccda2f745e767c46e9c6543b1169 + languageName: node + linkType: hard + +"dot-prop@npm:^5.1.0": + version: 5.3.0 + resolution: "dot-prop@npm:5.3.0" + dependencies: + is-obj: ^2.0.0 + checksum: d5775790093c234ef4bfd5fbe40884ff7e6c87573e5339432870616331189f7f5d86575c5b5af2dcf0f61172990f4f734d07844b1f23482fff09e3c4bead05ea + languageName: node + linkType: hard + +"dotenv@npm:~10.0.0": + version: 10.0.0 + resolution: "dotenv@npm:10.0.0" + checksum: f412c5fe8c24fbe313d302d2500e247ba8a1946492db405a4de4d30dd0eb186a88a43f13c958c5a7de303938949c4231c56994f97d05c4bc1f22478d631b4005 + languageName: node + linkType: hard + +"duplexer@npm:^0.1.1, duplexer@npm:^0.1.2": + version: 0.1.2 + resolution: "duplexer@npm:0.1.2" + checksum: 62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 + languageName: node + linkType: hard + +"duplexify@npm:^4.1.2": + version: 4.1.2 + resolution: "duplexify@npm:4.1.2" + dependencies: + end-of-stream: ^1.4.1 + inherits: ^2.0.3 + readable-stream: ^3.1.1 + stream-shift: ^1.0.0 + checksum: 964376c61c0e92f6ed0694b3ba97c84f199413dc40ab8dfdaef80b7a7f4982fcabf796214e28ed614a5bc1ec45488a29b81e7d46fa3f5ddf65bcb118c20145ad + languageName: node + linkType: hard + +"duplicate-package-checker-webpack-plugin@npm:^3.0.0": + version: 3.0.0 + resolution: "duplicate-package-checker-webpack-plugin@npm:3.0.0" + dependencies: + chalk: ^2.3.0 + find-root: ^1.0.0 + lodash: ^4.17.4 + semver: ^5.4.1 + checksum: d77be45cb72d79a429c64d8f8f7603fea681d182fb795459a3d4afa608faad9a923378a7e80c6855f465263e1983140b6fc3682bd0213228b8cd7906ab4b934d + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed + languageName: node + linkType: hard + +"ecc-jsbn@npm:~0.1.1": + version: 0.1.2 + resolution: "ecc-jsbn@npm:0.1.2" + dependencies: + jsbn: ~0.1.0 + safer-buffer: ^2.1.0 + checksum: 22fef4b6203e5f31d425f5b711eb389e4c6c2723402e389af394f8411b76a488fa414d309d866e2b577ce3e8462d344205545c88a8143cc21752a5172818888a + languageName: node + linkType: hard + +"ecdsa-sig-formatter@npm:1.0.11": + version: 1.0.11 + resolution: "ecdsa-sig-formatter@npm:1.0.11" + dependencies: + safe-buffer: ^5.0.1 + checksum: 207f9ab1c2669b8e65540bce29506134613dd5f122cccf1e6a560f4d63f2732d427d938f8481df175505aad94583bcb32c688737bb39a6df0625f903d6d93c03 + languageName: node + linkType: hard + +"ee-first@npm:1.1.1": + version: 1.1.1 + resolution: "ee-first@npm:1.1.1" + checksum: 1b4cac778d64ce3b582a7e26b218afe07e207a0f9bfe13cc7395a6d307849cfe361e65033c3251e00c27dd060cab43014c2d6b2647676135e18b77d2d05b3f4f + languageName: node + linkType: hard + +"ejs@npm:^3.1.7": + version: 3.1.8 + resolution: "ejs@npm:3.1.8" + dependencies: + jake: ^10.8.5 + bin: + ejs: bin/cli.js + checksum: 1d40d198ad52e315ccf37e577bdec06e24eefdc4e3c27aafa47751a03a0c7f0ec4310254c9277a5f14763c3cd4bbacce27497332b2d87c74232b9b1defef8efc + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.4.284": + version: 1.4.327 + resolution: "electron-to-chromium@npm:1.4.327" + checksum: 91f0b399f1752be629c86bf49eef391352a07b41e1d26b1fa9331cb88e558d6139ad569e2edba99550c8afcd2691d9eacc2523102d5957030818e173eb335b13 + languageName: node + linkType: hard + +"emittery@npm:^0.13.1": + version: 0.13.1 + resolution: "emittery@npm:0.13.1" + checksum: 2b089ab6306f38feaabf4f6f02792f9ec85fc054fda79f44f6790e61bbf6bc4e1616afb9b232e0c5ec5289a8a452f79bfa6d905a6fd64e94b49981f0934001c6 + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 + languageName: node + linkType: hard + +"emojis-list@npm:^3.0.0": + version: 3.0.0 + resolution: "emojis-list@npm:3.0.0" + checksum: ddaaa02542e1e9436c03970eeed445f4ed29a5337dfba0fe0c38dfdd2af5da2429c2a0821304e8a8d1cadf27fdd5b22ff793571fa803ae16852a6975c65e8e70 + languageName: node + linkType: hard + +"encodeurl@npm:~1.0.2": + version: 1.0.2 + resolution: "encodeurl@npm:1.0.2" + checksum: e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: ^0.6.2 + checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f + languageName: node + linkType: hard + +"end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.1": + version: 1.4.4 + resolution: "end-of-stream@npm:1.4.4" + dependencies: + once: ^1.4.0 + checksum: 530a5a5a1e517e962854a31693dbb5c0b2fc40b46dad2a56a2deec656ca040631124f4795823acc68238147805f8b021abbe221f4afed5ef3c8e8efc2024908b + languageName: node + linkType: hard + +"end-of-stream@npm:~1.1.0": + version: 1.1.0 + resolution: "end-of-stream@npm:1.1.0" + dependencies: + once: ~1.3.0 + checksum: 9fa637e259e50e5e3634e8e14064a183bd0d407733594631362f9df596409739bef5f7064840e6725212a9edc8b4a70a5a3088ac423e8564f9dc183dd098c719 + languageName: node + linkType: hard + +"enhanced-resolve@npm:^5.10.0": + version: 5.12.0 + resolution: "enhanced-resolve@npm:5.12.0" + dependencies: + graceful-fs: ^4.2.4 + tapable: ^2.2.0 + checksum: bf3f787facaf4ce3439bef59d148646344e372bef5557f0d37ea8aa02c51f50a925cd1f07b8d338f18992c29f544ec235a8c64bcdb56030196c48832a5494174 + languageName: node + linkType: hard + +"enquirer@npm:~2.3.6": + version: 2.3.6 + resolution: "enquirer@npm:2.3.6" + dependencies: + ansi-colors: ^4.1.1 + checksum: 1c0911e14a6f8d26721c91e01db06092a5f7675159f0261d69c403396a385afd13dd76825e7678f66daffa930cfaa8d45f506fb35f818a2788463d022af1b884 + languageName: node + linkType: hard + +"entities@npm:^2.0.0": + version: 2.2.0 + resolution: "entities@npm:2.2.0" + checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 + languageName: node + linkType: hard + +"entities@npm:^4.2.0, entities@npm:^4.3.0, entities@npm:^4.4.0": + version: 4.4.0 + resolution: "entities@npm:4.4.0" + checksum: 84d250329f4b56b40fa93ed067b194db21e8815e4eb9b59f43a086f0ecd342814f6bc483de8a77da5d64e0f626033192b1b4f1792232a7ea6b970ebe0f3187c2 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e + languageName: node + linkType: hard + +"envinfo@npm:7.8.1, envinfo@npm:^7.7.3": + version: 7.8.1 + resolution: "envinfo@npm:7.8.1" + bin: + envinfo: dist/cli.js + checksum: de736c98d6311c78523628ff127af138451b162e57af5293c1b984ca821d0aeb9c849537d2fde0434011bed33f6bca5310ca2aab8a51a3f28fc719e89045d648 + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 + languageName: node + linkType: hard + +"error-ex@npm:^1.3.1": + version: 1.3.2 + resolution: "error-ex@npm:1.3.2" + dependencies: + is-arrayish: ^0.2.1 + checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 + languageName: node + linkType: hard + +"es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4": + version: 1.21.1 + resolution: "es-abstract@npm:1.21.1" + dependencies: + available-typed-arrays: ^1.0.5 + call-bind: ^1.0.2 + es-set-tostringtag: ^2.0.1 + es-to-primitive: ^1.2.1 + function-bind: ^1.1.1 + function.prototype.name: ^1.1.5 + get-intrinsic: ^1.1.3 + get-symbol-description: ^1.0.0 + globalthis: ^1.0.3 + gopd: ^1.0.1 + has: ^1.0.3 + has-property-descriptors: ^1.0.0 + has-proto: ^1.0.1 + has-symbols: ^1.0.3 + internal-slot: ^1.0.4 + is-array-buffer: ^3.0.1 + is-callable: ^1.2.7 + is-negative-zero: ^2.0.2 + is-regex: ^1.1.4 + is-shared-array-buffer: ^1.0.2 + is-string: ^1.0.7 + is-typed-array: ^1.1.10 + is-weakref: ^1.0.2 + object-inspect: ^1.12.2 + object-keys: ^1.1.1 + object.assign: ^4.1.4 + regexp.prototype.flags: ^1.4.3 + safe-regex-test: ^1.0.0 + string.prototype.trimend: ^1.0.6 + string.prototype.trimstart: ^1.0.6 + typed-array-length: ^1.0.4 + unbox-primitive: ^1.0.2 + which-typed-array: ^1.1.9 + checksum: 23ff60d42d17a55d150e7bcedbdb065d4077a8b98c436e0e2e1ef4dd532a6d78a56028673de0bd8ed464a43c46ba781c50d9af429b6a17e44dbd14c7d7fb7926 + languageName: node + linkType: hard + +"es-module-lexer@npm:^0.9.0": + version: 0.9.3 + resolution: "es-module-lexer@npm:0.9.3" + checksum: 84bbab23c396281db2c906c766af58b1ae2a1a2599844a504df10b9e8dc77ec800b3211fdaa133ff700f5703d791198807bba25d9667392d27a5e9feda344da8 + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.0.1": + version: 2.0.1 + resolution: "es-set-tostringtag@npm:2.0.1" + dependencies: + get-intrinsic: ^1.1.3 + has: ^1.0.3 + has-tostringtag: ^1.0.0 + checksum: ec416a12948cefb4b2a5932e62093a7cf36ddc3efd58d6c58ca7ae7064475ace556434b869b0bbeb0c365f1032a8ccd577211101234b69837ad83ad204fff884 + languageName: node + linkType: hard + +"es-shim-unscopables@npm:^1.0.0": + version: 1.0.0 + resolution: "es-shim-unscopables@npm:1.0.0" + dependencies: + has: ^1.0.3 + checksum: 83e95cadbb6ee44d3644dfad60dcad7929edbc42c85e66c3e99aefd68a3a5c5665f2686885cddb47dfeabfd77bd5ea5a7060f2092a955a729bbd8834f0d86fa1 + languageName: node + linkType: hard + +"es-to-primitive@npm:^1.2.1": + version: 1.2.1 + resolution: "es-to-primitive@npm:1.2.1" + dependencies: + is-callable: ^1.1.4 + is-date-object: ^1.0.1 + is-symbol: ^1.0.2 + checksum: 4ead6671a2c1402619bdd77f3503991232ca15e17e46222b0a41a5d81aebc8740a77822f5b3c965008e631153e9ef0580540007744521e72de8e33599fca2eed + languageName: node + linkType: hard + +"es5-ext@npm:^0.10.35, es5-ext@npm:^0.10.46, es5-ext@npm:^0.10.50, es5-ext@npm:^0.10.53, es5-ext@npm:~0.10.14, es5-ext@npm:~0.10.2, es5-ext@npm:~0.10.46": + version: 0.10.62 + resolution: "es5-ext@npm:0.10.62" + dependencies: + es6-iterator: ^2.0.3 + es6-symbol: ^3.1.3 + next-tick: ^1.1.0 + checksum: 25f42f6068cfc6e393cf670bc5bba249132c5f5ec2dd0ed6e200e6274aca2fed8e9aec8a31c76031744c78ca283c57f0b41c7e737804c6328c7b8d3fbcba7983 + languageName: node + linkType: hard + +"es6-iterator@npm:^2.0.3": + version: 2.0.3 + resolution: "es6-iterator@npm:2.0.3" + dependencies: + d: 1 + es5-ext: ^0.10.35 + es6-symbol: ^3.1.1 + checksum: 6e48b1c2d962c21dee604b3d9f0bc3889f11ed5a8b33689155a2065d20e3107e2a69cc63a71bd125aeee3a589182f8bbcb5c8a05b6a8f38fa4205671b6d09697 + languageName: node + linkType: hard + +"es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3": + version: 3.1.3 + resolution: "es6-symbol@npm:3.1.3" + dependencies: + d: ^1.0.1 + ext: ^1.1.2 + checksum: cd49722c2a70f011eb02143ef1c8c70658d2660dead6641e160b94619f408b9cf66425515787ffe338affdf0285ad54f4eae30ea5bd510e33f8659ec53bcaa70 + languageName: node + linkType: hard + +"es6-weak-map@npm:^2.0.3": + version: 2.0.3 + resolution: "es6-weak-map@npm:2.0.3" + dependencies: + d: 1 + es5-ext: ^0.10.46 + es6-iterator: ^2.0.3 + es6-symbol: ^3.1.1 + checksum: 19ca15f46d50948ce78c2da5f21fb5b1ef45addd4fe17b5df952ff1f2a3d6ce4781249bc73b90995257264be2a98b2ec749bb2aba0c14b5776a1154178f9c927 + languageName: node + linkType: hard + +"escalade@npm:^3.1.1": + version: 3.1.1 + resolution: "escalade@npm:3.1.1" + checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 + languageName: node + linkType: hard + +"escape-html@npm:~1.0.3": + version: 1.0.3 + resolution: "escape-html@npm:1.0.3" + checksum: 6213ca9ae00d0ab8bccb6d8d4e0a98e76237b2410302cf7df70aaa6591d509a2a37ce8998008cbecae8fc8ffaadf3fb0229535e6a145f3ce0b211d060decbb24 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^1.0.5": + version: 1.0.5 + resolution: "escape-string-regexp@npm:1.0.5" + checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^2.0.0": + version: 2.0.0 + resolution: "escape-string-regexp@npm:2.0.0" + checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-string-regexp@npm:4.0.0" + checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e + languageName: node + linkType: hard + +"escodegen@npm:^2.0.0": + version: 2.0.0 + resolution: "escodegen@npm:2.0.0" + dependencies: + esprima: ^4.0.1 + estraverse: ^5.2.0 + esutils: ^2.0.2 + optionator: ^0.8.1 + source-map: ~0.6.1 + dependenciesMeta: + source-map: + optional: true + bin: + escodegen: bin/escodegen.js + esgenerate: bin/esgenerate.js + checksum: 5aa6b2966fafe0545e4e77936300cc94ad57cfe4dc4ebff9950492eaba83eef634503f12d7e3cbd644ecc1bab388ad0e92b06fd32222c9281a75d1cf02ec6cef + languageName: node + linkType: hard + +"eslint-config-prettier@npm:~8.7.0": + version: 8.7.0 + resolution: "eslint-config-prettier@npm:8.7.0" + peerDependencies: + eslint: ">=7.0.0" + bin: + eslint-config-prettier: bin/cli.js + checksum: b05bc7f2296ce3e0925c14147849706544870e0382d38af2352d709a6cf8521bdaff2bd8e5021f1780e570775a8ffa1d2bac28b8065d90d43a3f1f98fd26ce52 + languageName: node + linkType: hard + +"eslint-plugin-jest@npm:~27.2.1": + version: 27.2.1 + resolution: "eslint-plugin-jest@npm:27.2.1" + dependencies: + "@typescript-eslint/utils": ^5.10.0 + peerDependencies: + "@typescript-eslint/eslint-plugin": ^5.0.0 + eslint: ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + "@typescript-eslint/eslint-plugin": + optional: true + jest: + optional: true + checksum: 579a4d26304cc6748b2e6dff6c965ea7a21b618d8b051eb02727d25cf5c7767f6db8ef5237531635ff77e242b983b973e7cb8c820a4d20d5bda73358c452a8ab + languageName: node + linkType: hard + +"eslint-plugin-prettier@npm:~5.0.0": + version: 5.0.0 + resolution: "eslint-plugin-prettier@npm:5.0.0" + dependencies: + prettier-linter-helpers: ^1.0.0 + synckit: ^0.8.5 + peerDependencies: + "@types/eslint": ">=8.0.0" + eslint: ">=8.0.0" + prettier: ">=3.0.0" + peerDependenciesMeta: + "@types/eslint": + optional: true + eslint-config-prettier: + optional: true + checksum: 84e88744b9050f2d5ef31b94e85294dda16f3a53c2449f9d33eac8ae6264889b459bf35a68e438fb6b329c2a1d6491aac4bfa00d86317e7009de3dad0311bec6 + languageName: node + linkType: hard + +"eslint-plugin-react@npm:~7.32.2": + version: 7.32.2 + resolution: "eslint-plugin-react@npm:7.32.2" + dependencies: + array-includes: ^3.1.6 + array.prototype.flatmap: ^1.3.1 + array.prototype.tosorted: ^1.1.1 + doctrine: ^2.1.0 + estraverse: ^5.3.0 + jsx-ast-utils: ^2.4.1 || ^3.0.0 + minimatch: ^3.1.2 + object.entries: ^1.1.6 + object.fromentries: ^2.0.6 + object.hasown: ^1.1.2 + object.values: ^1.1.6 + prop-types: ^15.8.1 + resolve: ^2.0.0-next.4 + semver: ^6.3.0 + string.prototype.matchall: ^4.0.8 + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + checksum: 2232b3b8945aa50b7773919c15cd96892acf35d2f82503667a79e2f55def90f728ed4f0e496f0f157acbe1bd4397c5615b676ae7428fe84488a544ca53feb944 + languageName: node + linkType: hard + +"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: ^4.3.0 + estraverse: ^4.1.1 + checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb + languageName: node + linkType: hard + +"eslint-scope@npm:^7.1.1": + version: 7.1.1 + resolution: "eslint-scope@npm:7.1.1" + dependencies: + esrecurse: ^4.3.0 + estraverse: ^5.2.0 + checksum: 9f6e974ab2db641ca8ab13508c405b7b859e72afe9f254e8131ff154d2f40c99ad4545ce326fd9fde3212ff29707102562a4834f1c48617b35d98c71a97fbf3e + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^3.3.0": + version: 3.3.0 + resolution: "eslint-visitor-keys@npm:3.3.0" + checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808 + languageName: node + linkType: hard + +"eslint@npm:~8.36.0": + version: 8.36.0 + resolution: "eslint@npm:8.36.0" + dependencies: + "@eslint-community/eslint-utils": ^4.2.0 + "@eslint-community/regexpp": ^4.4.0 + "@eslint/eslintrc": ^2.0.1 + "@eslint/js": 8.36.0 + "@humanwhocodes/config-array": ^0.11.8 + "@humanwhocodes/module-importer": ^1.0.1 + "@nodelib/fs.walk": ^1.2.8 + ajv: ^6.10.0 + chalk: ^4.0.0 + cross-spawn: ^7.0.2 + debug: ^4.3.2 + doctrine: ^3.0.0 + escape-string-regexp: ^4.0.0 + eslint-scope: ^7.1.1 + eslint-visitor-keys: ^3.3.0 + espree: ^9.5.0 + esquery: ^1.4.2 + esutils: ^2.0.2 + fast-deep-equal: ^3.1.3 + file-entry-cache: ^6.0.1 + find-up: ^5.0.0 + glob-parent: ^6.0.2 + globals: ^13.19.0 + grapheme-splitter: ^1.0.4 + ignore: ^5.2.0 + import-fresh: ^3.0.0 + imurmurhash: ^0.1.4 + is-glob: ^4.0.0 + is-path-inside: ^3.0.3 + js-sdsl: ^4.1.4 + js-yaml: ^4.1.0 + json-stable-stringify-without-jsonify: ^1.0.1 + levn: ^0.4.1 + lodash.merge: ^4.6.2 + minimatch: ^3.1.2 + natural-compare: ^1.4.0 + optionator: ^0.9.1 + strip-ansi: ^6.0.1 + strip-json-comments: ^3.1.0 + text-table: ^0.2.0 + bin: + eslint: bin/eslint.js + checksum: e9a961fc3b3de5cff5a1cb2c92eeffaa7e155a715489e30b3e1e76f186bd1255e0481e09564f2094733c0b1dbd3453499fb72ae7c043c83156e11e6d965b2304 + languageName: node + linkType: hard + +"esm@npm:^3.2.25": + version: 3.2.25 + resolution: "esm@npm:3.2.25" + checksum: 978aabe2de83541c105605a6d60a26ed8e627ef6bb0a7605fe15a95bbdea6b8348bd045255cb22219c054dd09a81a94823df00843d9e97f42419c92015ce3a64 + languageName: node + linkType: hard + +"espree@npm:^9.5.0": + version: 9.5.0 + resolution: "espree@npm:9.5.0" + dependencies: + acorn: ^8.8.0 + acorn-jsx: ^5.3.2 + eslint-visitor-keys: ^3.3.0 + checksum: a7f110aefb6407e0d3237aa635ab3cea87106ae63748dd23c67031afccc640d04c4209fca2daf16e2233c82efb505faead0fb84097478fd9cc6e8f8dd80bf99d + languageName: node + linkType: hard + +"esprima@npm:^4.0.0, esprima@npm:^4.0.1": + version: 4.0.1 + resolution: "esprima@npm:4.0.1" + bin: + esparse: ./bin/esparse.js + esvalidate: ./bin/esvalidate.js + checksum: b45bc805a613dbea2835278c306b91aff6173c8d034223fa81498c77dcbce3b2931bf6006db816f62eacd9fd4ea975dfd85a5b7f3c6402cfd050d4ca3c13a628 + languageName: node + linkType: hard + +"esquery@npm:^1.4.2": + version: 1.5.0 + resolution: "esquery@npm:1.5.0" + dependencies: + estraverse: ^5.1.0 + checksum: aefb0d2596c230118656cd4ec7532d447333a410a48834d80ea648b1e7b5c9bc9ed8b5e33a89cb04e487b60d622f44cf5713bf4abed7c97343edefdc84a35900 + languageName: node + linkType: hard + +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: ^5.2.0 + checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837 + languageName: node + linkType: hard + +"estraverse@npm:^4.1.1": + version: 4.3.0 + resolution: "estraverse@npm:4.3.0" + checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827 + languageName: node + linkType: hard + +"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": + version: 5.3.0 + resolution: "estraverse@npm:5.3.0" + checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b + languageName: node + linkType: hard + +"esutils@npm:^2.0.2": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 + languageName: node + linkType: hard + +"etag@npm:~1.8.1": + version: 1.8.1 + resolution: "etag@npm:1.8.1" + checksum: 571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff + languageName: node + linkType: hard + +"event-emitter@npm:^0.3.5": + version: 0.3.5 + resolution: "event-emitter@npm:0.3.5" + dependencies: + d: 1 + es5-ext: ~0.10.14 + checksum: 27c1399557d9cd7e0aa0b366c37c38a4c17293e3a10258e8b692a847dd5ba9fb90429c3a5a1eeff96f31f6fa03ccbd31d8ad15e00540b22b22f01557be706030 + languageName: node + linkType: hard + +"event-target-shim@npm:^5.0.0": + version: 5.0.1 + resolution: "event-target-shim@npm:5.0.1" + checksum: 1ffe3bb22a6d51bdeb6bf6f7cf97d2ff4a74b017ad12284cc9e6a279e727dc30a5de6bb613e5596ff4dc3e517841339ad09a7eec44266eccb1aa201a30448166 + languageName: node + linkType: hard + +"eventemitter3@npm:^4.0.4": + version: 4.0.7 + resolution: "eventemitter3@npm:4.0.7" + checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 + languageName: node + linkType: hard + +"events@npm:^3.2.0, events@npm:^3.3.0": + version: 3.3.0 + resolution: "events@npm:3.3.0" + checksum: f6f487ad2198aa41d878fa31452f1a3c00958f46e9019286ff4787c84aac329332ab45c9cdc8c445928fc6d7ded294b9e005a7fce9426488518017831b272780 + languageName: node + linkType: hard + +"execa@npm:5.0.0, execa@npm:^5.0.0": + version: 5.0.0 + resolution: "execa@npm:5.0.0" + dependencies: + cross-spawn: ^7.0.3 + get-stream: ^6.0.0 + human-signals: ^2.1.0 + is-stream: ^2.0.0 + merge-stream: ^2.0.0 + npm-run-path: ^4.0.1 + onetime: ^5.1.2 + signal-exit: ^3.0.3 + strip-final-newline: ^2.0.0 + checksum: a044367ebdcc68ca019810cb134510fc77bbc55c799122258ee0e00e289c132941ab48c2a331a036699c42bc8d479d451ae67c105fce5ce5cc813e7dd92d642b + languageName: node + linkType: hard + +"execa@npm:^7.1.1": + version: 7.1.1 + resolution: "execa@npm:7.1.1" + dependencies: + cross-spawn: ^7.0.3 + get-stream: ^6.0.1 + human-signals: ^4.3.0 + is-stream: ^3.0.0 + merge-stream: ^2.0.0 + npm-run-path: ^5.1.0 + onetime: ^6.0.0 + signal-exit: ^3.0.7 + strip-final-newline: ^3.0.0 + checksum: 21fa46fc69314ace4068cf820142bdde5b643a5d89831c2c9349479c1555bff137a291b8e749e7efca36535e4e0a8c772c11008ca2e84d2cbd6ca141a3c8f937 + languageName: node + linkType: hard + +"exit@npm:^0.1.2": + version: 0.1.2 + resolution: "exit@npm:0.1.2" + checksum: abc407f07a875c3961e4781dfcb743b58d6c93de9ab263f4f8c9d23bb6da5f9b7764fc773f86b43dd88030444d5ab8abcb611cb680fba8ca075362b77114bba3 + languageName: node + linkType: hard + +"expect@npm:^29.0.0, expect@npm:^29.5.0": + version: 29.5.0 + resolution: "expect@npm:29.5.0" + dependencies: + "@jest/expect-utils": ^29.5.0 + jest-get-type: ^29.4.3 + jest-matcher-utils: ^29.5.0 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + checksum: 58f70b38693df6e5c6892db1bcd050f0e518d6f785175dc53917d4fa6a7359a048e5690e19ddcb96b65c4493881dd89a3dabdab1a84dfa55c10cdbdabf37b2d7 + languageName: node + linkType: hard + +"express-rate-limit@npm:5.5.1": + version: 5.5.1 + resolution: "express-rate-limit@npm:5.5.1" + checksum: 264820bd5fe350794f90497c5bdc7b323eec4394873cd4b9f9d3654b2c47b285e87270a5a11721fb7fb895d56218e9657ea7bb9a544dd43770c6e7beaad217e8 + languageName: node + linkType: hard + +"express@npm:4.18.2": + version: 4.18.2 + resolution: "express@npm:4.18.2" + dependencies: + accepts: ~1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: ~1.0.4 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + etag: ~1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: ~1.1.2 + on-finished: 2.4.1 + parseurl: ~1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: ~2.0.7 + qs: 6.11.0 + range-parser: ~1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: ~1.6.18 + utils-merge: 1.0.1 + vary: ~1.1.2 + checksum: 3c4b9b076879442f6b968fe53d85d9f1eeacbb4f4c41e5f16cc36d77ce39a2b0d81b3f250514982110d815b2f7173f5561367f9110fcc541f9371948e8c8b037 + languageName: node + linkType: hard + +"ext@npm:^1.1.2": + version: 1.7.0 + resolution: "ext@npm:1.7.0" + dependencies: + type: ^2.7.2 + checksum: ef481f9ef45434d8c867cfd09d0393b60945b7c8a1798bedc4514cb35aac342ccb8d8ecb66a513e6a2b4ec1e294a338e3124c49b29736f8e7c735721af352c31 + languageName: node + linkType: hard + +"extend@npm:~3.0.2": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 + languageName: node + linkType: hard + +"external-editor@npm:^3.0.3": + version: 3.1.0 + resolution: "external-editor@npm:3.1.0" + dependencies: + chardet: ^0.7.0 + iconv-lite: ^0.4.24 + tmp: ^0.0.33 + checksum: 1c2a616a73f1b3435ce04030261bed0e22d4737e14b090bb48e58865da92529c9f2b05b893de650738d55e692d071819b45e1669259b2b354bc3154d27a698c7 + languageName: node + linkType: hard + +"extsprintf@npm:1.3.0, extsprintf@npm:^1.2.0": + version: 1.3.0 + resolution: "extsprintf@npm:1.3.0" + checksum: cee7a4a1e34cffeeec18559109de92c27517e5641991ec6bab849aa64e3081022903dd53084f2080d0d2530803aa5ee84f1e9de642c365452f9e67be8f958ce2 + languageName: node + linkType: hard + +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3, fast-deep-equal@npm:~3.1.3": + version: 3.1.3 + resolution: "fast-deep-equal@npm:3.1.3" + checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d + languageName: node + linkType: hard + +"fast-diff@npm:^1.1.2": + version: 1.2.0 + resolution: "fast-diff@npm:1.2.0" + checksum: 1b5306eaa9e826564d9e5ffcd6ebd881eb5f770b3f977fcbf38f05c824e42172b53c79920e8429c54eb742ce15a0caf268b0fdd5b38f6de52234c4a8368131ae + languageName: node + linkType: hard + +"fast-glob@npm:3.2.7": + version: 3.2.7 + resolution: "fast-glob@npm:3.2.7" + dependencies: + "@nodelib/fs.stat": ^2.0.2 + "@nodelib/fs.walk": ^1.2.3 + glob-parent: ^5.1.2 + merge2: ^1.3.0 + micromatch: ^4.0.4 + checksum: 2f4708ff112d2b451888129fdd9a0938db88b105b0ddfd043c064e3c4d3e20eed8d7c7615f7565fee660db34ddcf08a2db1bf0ab3c00b87608e4719694642d78 + languageName: node + linkType: hard + +"fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.2, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": + version: 3.3.1 + resolution: "fast-glob@npm:3.3.1" + dependencies: + "@nodelib/fs.stat": ^2.0.2 + "@nodelib/fs.walk": ^1.2.3 + glob-parent: ^5.1.2 + merge2: ^1.3.0 + micromatch: ^4.0.4 + checksum: b6f3add6403e02cf3a798bfbb1183d0f6da2afd368f27456010c0bc1f9640aea308243d4cb2c0ab142f618276e65ecb8be1661d7c62a7b4e5ba774b9ce5432e5 + languageName: node + linkType: hard + +"fast-json-patch@npm:^3.1.1": + version: 3.1.1 + resolution: "fast-json-patch@npm:3.1.1" + checksum: c4525b61b2471df60d4b025b4118b036d99778a93431aa44d1084218182841d82ce93056f0f3bbd731a24e6a8e69820128adf1873eb2199a26c62ef58d137833 + languageName: node + linkType: hard + +"fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0, fast-json-stable-stringify@npm:~2.1.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb + languageName: node + linkType: hard + +"fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6": + version: 2.0.6 + resolution: "fast-levenshtein@npm:2.0.6" + checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c + languageName: node + linkType: hard + +"fast-redact@npm:^3.0.0": + version: 3.1.2 + resolution: "fast-redact@npm:3.1.2" + checksum: a30eb6b6830333ab213e0def55f46453ca777544dbd3a883016cb590a0eeb95e6fdf546553c1a13d509896bfba889b789991160a6d0996ceb19fce0a02e8b753 + languageName: node + linkType: hard + +"fast-safe-stringify@npm:2.1.1": + version: 2.1.1 + resolution: "fast-safe-stringify@npm:2.1.1" + checksum: a851cbddc451745662f8f00ddb622d6766f9bd97642dabfd9a405fb0d646d69fc0b9a1243cbf67f5f18a39f40f6fa821737651ff1bceeba06c9992ca2dc5bd3d + languageName: node + linkType: hard + +"fastest-levenshtein@npm:^1.0.12, fastest-levenshtein@npm:^1.0.16": + version: 1.0.16 + resolution: "fastest-levenshtein@npm:1.0.16" + checksum: a78d44285c9e2ae2c25f3ef0f8a73f332c1247b7ea7fb4a191e6bb51aa6ee1ef0dfb3ed113616dcdc7023e18e35a8db41f61c8d88988e877cf510df8edafbc71 + languageName: node + linkType: hard + +"fastq@npm:^1.6.0": + version: 1.15.0 + resolution: "fastq@npm:1.15.0" + dependencies: + reusify: ^1.0.4 + checksum: 0170e6bfcd5d57a70412440b8ef600da6de3b2a6c5966aeaf0a852d542daff506a0ee92d6de7679d1de82e644bce69d7a574a6c93f0b03964b5337eed75ada1a + languageName: node + linkType: hard + +"fb-watchman@npm:^2.0.0": + version: 2.0.2 + resolution: "fb-watchman@npm:2.0.2" + dependencies: + bser: 2.1.1 + checksum: b15a124cef28916fe07b400eb87cbc73ca082c142abf7ca8e8de6af43eca79ca7bd13eb4d4d48240b3bd3136eaac40d16e42d6edf87a8e5d1dd8070626860c78 + languageName: node + linkType: hard + +"figures@npm:3.2.0, figures@npm:^3.0.0": + version: 3.2.0 + resolution: "figures@npm:3.2.0" + dependencies: + escape-string-regexp: ^1.0.5 + checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b + languageName: node + linkType: hard + +"figures@npm:^5.0.0": + version: 5.0.0 + resolution: "figures@npm:5.0.0" + dependencies: + escape-string-regexp: ^5.0.0 + is-unicode-supported: ^1.2.0 + checksum: e6e8b6d1df2f554d4effae4a5ceff5d796f9449f6d4e912d74dab7d5f25916ecda6c305b9084833157d56485a0c78b37164430ddc5675bcee1330e346710669e + languageName: node + linkType: hard + +"file-entry-cache@npm:^6.0.1": + version: 6.0.1 + resolution: "file-entry-cache@npm:6.0.1" + dependencies: + flat-cache: ^3.0.4 + checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 + languageName: node + linkType: hard + +"filelist@npm:^1.0.1": + version: 1.0.4 + resolution: "filelist@npm:1.0.4" + dependencies: + minimatch: ^5.0.1 + checksum: a303573b0821e17f2d5e9783688ab6fbfce5d52aaac842790ae85e704a6f5e4e3538660a63183d6453834dedf1e0f19a9dadcebfa3e926c72397694ea11f5160 + languageName: node + linkType: hard + +"fill-range@npm:^7.0.1": + version: 7.0.1 + resolution: "fill-range@npm:7.0.1" + dependencies: + to-regex-range: ^5.0.1 + checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917 + languageName: node + linkType: hard + +"finalhandler@npm:1.2.0": + version: 1.2.0 + resolution: "finalhandler@npm:1.2.0" + dependencies: + debug: 2.6.9 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + on-finished: 2.4.1 + parseurl: ~1.3.3 + statuses: 2.0.1 + unpipe: ~1.0.0 + checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 + languageName: node + linkType: hard + +"find-root@npm:^1.0.0": + version: 1.1.0 + resolution: "find-root@npm:1.1.0" + checksum: b2a59fe4b6c932eef36c45a048ae8f93c85640212ebe8363164814990ee20f154197505965f3f4f102efc33bfb1cbc26fd17c4a2fc739ebc51b886b137cbefaf + languageName: node + linkType: hard + +"find-up@npm:^2.0.0": + version: 2.1.0 + resolution: "find-up@npm:2.1.0" + dependencies: + locate-path: ^2.0.0 + checksum: 43284fe4da09f89011f08e3c32cd38401e786b19226ea440b75386c1b12a4cb738c94969808d53a84f564ede22f732c8409e3cfc3f7fb5b5c32378ad0bbf28bd + languageName: node + linkType: hard + +"find-up@npm:^4.0.0, find-up@npm:^4.1.0": + version: 4.1.0 + resolution: "find-up@npm:4.1.0" + dependencies: + locate-path: ^5.0.0 + path-exists: ^4.0.0 + checksum: 4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 + languageName: node + linkType: hard + +"find-up@npm:^5.0.0": + version: 5.0.0 + resolution: "find-up@npm:5.0.0" + dependencies: + locate-path: ^6.0.0 + path-exists: ^4.0.0 + checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 + languageName: node + linkType: hard + +"flat-cache@npm:^3.0.4": + version: 3.0.4 + resolution: "flat-cache@npm:3.0.4" + dependencies: + flatted: ^3.1.0 + rimraf: ^3.0.2 + checksum: 4fdd10ecbcbf7d520f9040dd1340eb5dfe951e6f0ecf2252edeec03ee68d989ec8b9a20f4434270e71bcfd57800dc09b3344fca3966b2eb8f613072c7d9a2365 + languageName: node + linkType: hard + +"flat@npm:^5.0.2": + version: 5.0.2 + resolution: "flat@npm:5.0.2" + bin: + flat: cli.js + checksum: 12a1536ac746db74881316a181499a78ef953632ddd28050b7a3a43c62ef5462e3357c8c29d76072bb635f147f7a9a1f0c02efef6b4be28f8db62ceb3d5c7f5d + languageName: node + linkType: hard + +"flatted@npm:^3.1.0": + version: 3.2.7 + resolution: "flatted@npm:3.2.7" + checksum: 427633049d55bdb80201c68f7eb1cbd533e03eac541f97d3aecab8c5526f12a20ccecaeede08b57503e772c769e7f8680b37e8d482d1e5f8d7e2194687f9ea35 + languageName: node + linkType: hard + +"follow-redirects@npm:^1.15.0": + version: 1.15.2 + resolution: "follow-redirects@npm:1.15.2" + peerDependenciesMeta: + debug: + optional: true + checksum: faa66059b66358ba65c234c2f2a37fcec029dc22775f35d9ad6abac56003268baf41e55f9ee645957b32c7d9f62baf1f0b906e68267276f54ec4b4c597c2b190 + languageName: node + linkType: hard + +"for-each@npm:^0.3.3": + version: 0.3.3 + resolution: "for-each@npm:0.3.3" + dependencies: + is-callable: ^1.1.3 + checksum: 6c48ff2bc63362319c65e2edca4a8e1e3483a2fabc72fbe7feaf8c73db94fc7861bd53bc02c8a66a0c1dd709da6b04eec42e0abdd6b40ce47305ae92a25e5d28 + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.0": + version: 3.1.1 + resolution: "foreground-child@npm:3.1.1" + dependencies: + cross-spawn: ^7.0.0 + signal-exit: ^4.0.1 + checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 + languageName: node + linkType: hard + +"forever-agent@npm:~0.6.1": + version: 0.6.1 + resolution: "forever-agent@npm:0.6.1" + checksum: 766ae6e220f5fe23676bb4c6a99387cec5b7b62ceb99e10923376e27bfea72f3c3aeec2ba5f45f3f7ba65d6616965aa7c20b15002b6860833bb6e394dea546a8 + languageName: node + linkType: hard + +"form-data@npm:^3.0.0": + version: 3.0.1 + resolution: "form-data@npm:3.0.1" + dependencies: + asynckit: ^0.4.0 + combined-stream: ^1.0.8 + mime-types: ^2.1.12 + checksum: b019e8d35c8afc14a2bd8a7a92fa4f525a4726b6d5a9740e8d2623c30e308fbb58dc8469f90415a856698933c8479b01646a9dff33c87cc4e76d72aedbbf860d + languageName: node + linkType: hard + +"form-data@npm:^4.0.0": + version: 4.0.0 + resolution: "form-data@npm:4.0.0" + dependencies: + asynckit: ^0.4.0 + combined-stream: ^1.0.8 + mime-types: ^2.1.12 + checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c + languageName: node + linkType: hard + +"form-data@npm:~2.3.2": + version: 2.3.3 + resolution: "form-data@npm:2.3.3" + dependencies: + asynckit: ^0.4.0 + combined-stream: ^1.0.6 + mime-types: ^2.1.12 + checksum: 10c1780fa13dbe1ff3100114c2ce1f9307f8be10b14bf16e103815356ff567b6be39d70fc4a40f8990b9660012dc24b0f5e1dde1b6426166eb23a445ba068ca3 + languageName: node + linkType: hard + +"format-util@npm:^1.0.3": + version: 1.0.5 + resolution: "format-util@npm:1.0.5" + checksum: 0c8622e54ad899ca184ff0b4999e9ff9567965051bade140911209d60554c2ea4d43075763c1cf574d2f740966afe46469c9284357919505cdddf1a0b65ff85c + languageName: node + linkType: hard + +"forwarded@npm:0.2.0": + version: 0.2.0 + resolution: "forwarded@npm:0.2.0" + checksum: fd27e2394d8887ebd16a66ffc889dc983fbbd797d5d3f01087c020283c0f019a7d05ee85669383d8e0d216b116d720fc0cef2f6e9b7eb9f4c90c6e0bc7fd28e6 + languageName: node + linkType: hard + +"free-style@npm:3.1.0": + version: 3.1.0 + resolution: "free-style@npm:3.1.0" + checksum: 949258ae315deda48cac93ecd5f9a80f36e8a027e19ce2103598dc8d5ab60e963bbad5444b2a4990ddb746798dd188896f430285cf484afbf2141f7d75a191d8 + languageName: node + linkType: hard + +"fresh@npm:0.5.2": + version: 0.5.2 + resolution: "fresh@npm:0.5.2" + checksum: 13ea8b08f91e669a64e3ba3a20eb79d7ca5379a81f1ff7f4310d54e2320645503cc0c78daedc93dfb6191287295f6479544a649c64d8e41a1c0fb0c221552346 + languageName: node + linkType: hard + +"fs-constants@npm:^1.0.0": + version: 1.0.0 + resolution: "fs-constants@npm:1.0.0" + checksum: 18f5b718371816155849475ac36c7d0b24d39a11d91348cfcb308b4494824413e03572c403c86d3a260e049465518c4f0d5bd00f0371cdfcad6d4f30a85b350d + languageName: node + linkType: hard + +"fs-extra@npm:^10.1.0": + version: 10.1.0 + resolution: "fs-extra@npm:10.1.0" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: dc94ab37096f813cc3ca12f0f1b5ad6744dfed9ed21e953d72530d103cea193c2f81584a39e9dee1bea36de5ee66805678c0dddc048e8af1427ac19c00fffc50 + languageName: node + linkType: hard + +"fs-extra@npm:^11.1.0, fs-extra@npm:^11.1.1": + version: 11.1.1 + resolution: "fs-extra@npm:11.1.1" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd + languageName: node + linkType: hard + +"fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" + dependencies: + minipass: ^3.0.0 + checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.2 + resolution: "fs-minipass@npm:3.0.2" + dependencies: + minipass: ^5.0.0 + checksum: e9cc0e1f2d01c6f6f62f567aee59530aba65c6c7b2ae88c5027bc34c711ebcfcfaefd0caf254afa6adfe7d1fba16bc2537508a6235196bac7276747d078aef0a + languageName: node + linkType: hard + +"fs.realpath@npm:^1.0.0": + version: 1.0.0 + resolution: "fs.realpath@npm:1.0.0" + checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 + languageName: node + linkType: hard + +"fsevents@npm:2.3.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": + version: 2.3.2 + resolution: "fsevents@npm:2.3.2" + dependencies: + node-gyp: latest + checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@2.3.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": + version: 2.3.2 + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" + dependencies: + node-gyp: latest + conditions: os=darwin + languageName: node + linkType: hard + +"function-bind@npm:^1.1.1": + version: 1.1.1 + resolution: "function-bind@npm:1.1.1" + checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a + languageName: node + linkType: hard + +"function.prototype.name@npm:^1.1.5": + version: 1.1.5 + resolution: "function.prototype.name@npm:1.1.5" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + es-abstract: ^1.19.0 + functions-have-names: ^1.2.2 + checksum: acd21d733a9b649c2c442f067567743214af5fa248dbeee69d8278ce7df3329ea5abac572be9f7470b4ec1cd4d8f1040e3c5caccf98ebf2bf861a0deab735c27 + languageName: node + linkType: hard + +"functions-have-names@npm:^1.2.2": + version: 1.2.3 + resolution: "functions-have-names@npm:1.2.3" + checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5 + languageName: node + linkType: hard + +"gauge@npm:^3.0.0": + version: 3.0.2 + resolution: "gauge@npm:3.0.2" + dependencies: + aproba: ^1.0.3 || ^2.0.0 + color-support: ^1.1.2 + console-control-strings: ^1.0.0 + has-unicode: ^2.0.1 + object-assign: ^4.1.1 + signal-exit: ^3.0.0 + string-width: ^4.2.3 + strip-ansi: ^6.0.1 + wide-align: ^1.1.2 + checksum: 81296c00c7410cdd48f997800155fbead4f32e4f82109be0719c63edc8560e6579946cc8abd04205297640691ec26d21b578837fd13a4e96288ab4b40b1dc3e9 + languageName: node + linkType: hard + +"gauge@npm:^4.0.3": + version: 4.0.4 + resolution: "gauge@npm:4.0.4" + dependencies: + aproba: ^1.0.3 || ^2.0.0 + color-support: ^1.1.3 + console-control-strings: ^1.1.0 + has-unicode: ^2.0.1 + signal-exit: ^3.0.7 + string-width: ^4.2.3 + strip-ansi: ^6.0.1 + wide-align: ^1.1.5 + checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d + languageName: node + linkType: hard + +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec + languageName: node + linkType: hard + +"get-caller-file@npm:^2.0.5": + version: 2.0.5 + resolution: "get-caller-file@npm:2.0.5" + checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0": + version: 1.2.0 + resolution: "get-intrinsic@npm:1.2.0" + dependencies: + function-bind: ^1.1.1 + has: ^1.0.3 + has-symbols: ^1.0.3 + checksum: 78fc0487b783f5c58cf2dccafc3ae656ee8d2d8062a8831ce4a95e7057af4587a1d4882246c033aca0a7b4965276f4802b45cc300338d1b77a73d3e3e3f4877d + languageName: node + linkType: hard + +"get-package-type@npm:^0.1.0": + version: 0.1.0 + resolution: "get-package-type@npm:0.1.0" + checksum: bba0811116d11e56d702682ddef7c73ba3481f114590e705fc549f4d868972263896af313c57a25c076e3c0d567e11d919a64ba1b30c879be985fc9d44f96148 + languageName: node + linkType: hard + +"get-pkg-repo@npm:^4.2.1": + version: 4.2.1 + resolution: "get-pkg-repo@npm:4.2.1" + dependencies: + "@hutson/parse-repository-url": ^3.0.0 + hosted-git-info: ^4.0.0 + through2: ^2.0.0 + yargs: ^16.2.0 + bin: + get-pkg-repo: src/cli.js + checksum: 5abf169137665e45b09a857b33ad2fdcf2f4a09f0ecbd0ebdd789a7ce78c39186a21f58621127eb724d2d4a3a7ee8e6bd4ac7715efda01ad5200665afc218e0d + languageName: node + linkType: hard + +"get-port@npm:5.1.1": + version: 5.1.1 + resolution: "get-port@npm:5.1.1" + checksum: 0162663ffe5c09e748cd79d97b74cd70e5a5c84b760a475ce5767b357fb2a57cb821cee412d646aa8a156ed39b78aab88974eddaa9e5ee926173c036c0713787 + languageName: node + linkType: hard + +"get-stream@npm:6.0.0": + version: 6.0.0 + resolution: "get-stream@npm:6.0.0" + checksum: 587e6a93127f9991b494a566f4971cf7a2645dfa78034818143480a80587027bdd8826cdcf80d0eff4a4a19de0d231d157280f24789fc9cc31492e1dcc1290cf + languageName: node + linkType: hard + +"get-stream@npm:^5.1.0": + version: 5.2.0 + resolution: "get-stream@npm:5.2.0" + dependencies: + pump: ^3.0.0 + checksum: 8bc1a23174a06b2b4ce600df38d6c98d2ef6d84e020c1ddad632ad75bac4e092eeb40e4c09e0761c35fc2dbc5e7fff5dab5e763a383582c4a167dd69a905bd12 + languageName: node + linkType: hard + +"get-stream@npm:^6.0.0, get-stream@npm:^6.0.1": + version: 6.0.1 + resolution: "get-stream@npm:6.0.1" + checksum: e04ecece32c92eebf5b8c940f51468cd53554dcbb0ea725b2748be583c9523d00128137966afce410b9b051eb2ef16d657cd2b120ca8edafcf5a65e81af63cad + languageName: node + linkType: hard + +"get-symbol-description@npm:^1.0.0": + version: 1.0.0 + resolution: "get-symbol-description@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.1.1 + checksum: 9ceff8fe968f9270a37a1f73bf3f1f7bda69ca80f4f80850670e0e7b9444ff99323f7ac52f96567f8b5f5fbe7ac717a0d81d3407c7313e82810c6199446a5247 + languageName: node + linkType: hard + +"getpass@npm:^0.1.1": + version: 0.1.7 + resolution: "getpass@npm:0.1.7" + dependencies: + assert-plus: ^1.0.0 + checksum: ab18d55661db264e3eac6012c2d3daeafaab7a501c035ae0ccb193c3c23e9849c6e29b6ac762b9c2adae460266f925d55a3a2a3a3c8b94be2f222df94d70c046 + languageName: node + linkType: hard + +"git-hooks-list@npm:1.0.3": + version: 1.0.3 + resolution: "git-hooks-list@npm:1.0.3" + checksum: a1dd03d39c1d727ba08a35dbdbdcc6e96de8c4170c942dc95bf787ca6e34998d39fb5295a00242b58a3d265de0b69a0686d0cf583baa6b7830f268542c4576b9 + languageName: node + linkType: hard + +"git-raw-commits@npm:^3.0.0": + version: 3.0.0 + resolution: "git-raw-commits@npm:3.0.0" + dependencies: + dargs: ^7.0.0 + meow: ^8.1.2 + split2: ^3.2.2 + bin: + git-raw-commits: cli.js + checksum: 198892f307829d22fc8ec1c9b4a63876a1fde847763857bb74bd1b04c6f6bc0d7464340c25d0f34fd0fb395759363aa1f8ce324357027320d80523bf234676ab + languageName: node + linkType: hard + +"git-remote-origin-url@npm:^2.0.0": + version: 2.0.0 + resolution: "git-remote-origin-url@npm:2.0.0" + dependencies: + gitconfiglocal: ^1.0.0 + pify: ^2.3.0 + checksum: 85263a09c044b5f4fe2acc45cbb3c5331ab2bd4484bb53dfe7f3dd593a4bf90a9786a2e00b9884524331f50b3da18e8c924f01c2944087fc7f342282c4437b73 + languageName: node + linkType: hard + +"git-semver-tags@npm:^5.0.0": + version: 5.0.0 + resolution: "git-semver-tags@npm:5.0.0" + dependencies: + meow: ^8.1.2 + semver: ^6.3.0 + bin: + git-semver-tags: cli.js + checksum: 837d47ba46711e464fbddc6850adb1d8e715e1529ef0951171cbd7fcba3e44b2cb8011f66a9c9e1b86d687178a55258b061fbedf7c23afdc3f116f26be565aa4 + languageName: node + linkType: hard + +"git-up@npm:^7.0.0": + version: 7.0.0 + resolution: "git-up@npm:7.0.0" + dependencies: + is-ssh: ^1.4.0 + parse-url: ^8.1.0 + checksum: 2faadbab51e94d2ffb220e426e950087cc02c15d664e673bd5d1f734cfa8196fed8b19493f7bf28fe216d087d10e22a7fd9b63687e0ba7d24f0ddcfb0a266d6e + languageName: node + linkType: hard + +"git-url-parse@npm:13.1.0": + version: 13.1.0 + resolution: "git-url-parse@npm:13.1.0" + dependencies: + git-up: ^7.0.0 + checksum: 212a9b0343e9199998b6a532efe2014476a7a1283af393663ca49ac28d4768929aad16d3322e2685236065ee394dbc93e7aa63a48956531e984c56d8b5edb54d + languageName: node + linkType: hard + +"gitconfiglocal@npm:^1.0.0": + version: 1.0.0 + resolution: "gitconfiglocal@npm:1.0.0" + dependencies: + ini: ^1.3.2 + checksum: e6d2764c15bbab6d1d1000d1181bb907f6b3796bb04f63614dba571b18369e0ecb1beaf27ce8da5b24307ef607e3a5f262a67cb9575510b9446aac697d421beb + languageName: node + linkType: hard + +"glob-parent@npm:5.1.2, glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: ^4.0.1 + checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e + languageName: node + linkType: hard + +"glob-parent@npm:^6.0.1, glob-parent@npm:^6.0.2": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" + dependencies: + is-glob: ^4.0.3 + checksum: c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 + languageName: node + linkType: hard + +"glob-to-regexp@npm:^0.4.1": + version: 0.4.1 + resolution: "glob-to-regexp@npm:0.4.1" + checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167 + languageName: node + linkType: hard + +"glob@npm:7.1.4": + version: 7.1.4 + resolution: "glob@npm:7.1.4" + 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 + checksum: f52480fc82b1e66e52990f0f2e7306447d12294c83fbbee0395e761ad1178172012a7cc0673dbf4810baac400fc09bf34484c08b5778c216403fd823db281716 + languageName: node + linkType: hard + +"glob@npm:^10.2.2": + version: 10.3.0 + resolution: "glob@npm:10.3.0" + dependencies: + foreground-child: ^3.1.0 + jackspeak: ^2.0.3 + minimatch: ^9.0.1 + minipass: ^5.0.0 || ^6.0.2 + path-scurry: ^1.7.0 + bin: + glob: dist/cjs/src/bin.js + checksum: 6fa4ac0a86ffec1c5715a2e6fbdd63e1e7f1c2c8f5db08cc3256cdfcb81093678e7c80a3d100b502a1b9d141369ecf87bc24fe2bcb72acec7b14626d358a4eb0 + languageName: node + linkType: hard + +"glob@npm:^6.0.1": + version: 6.0.4 + resolution: "glob@npm:6.0.4" + dependencies: + inflight: ^1.0.4 + inherits: 2 + minimatch: 2 || 3 + once: ^1.3.0 + path-is-absolute: ^1.0.0 + checksum: c4946c3d015ac81f704d185f2b3a55eb670100693c2cf7bc833d0efd970ec727d860d4839a5178e46a7e594b34a34661bae2f4c3405727c9fd189f84954ca3c0 + languageName: node + linkType: hard + +"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:~7.1.6": + version: 7.1.7 + resolution: "glob@npm:7.1.7" + 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 + checksum: b61f48973bbdcf5159997b0874a2165db572b368b931135832599875919c237fc05c12984e38fe828e69aa8a921eb0e8a4997266211c517c9cfaae8a93988bb8 + languageName: node + linkType: hard + +"glob@npm:^8.0.1": + version: 8.1.0 + resolution: "glob@npm:8.1.0" + dependencies: + fs.realpath: ^1.0.0 + inflight: ^1.0.4 + inherits: 2 + minimatch: ^5.0.1 + once: ^1.3.0 + checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47 + languageName: node + linkType: hard + +"glob@npm:^9.2.0": + version: 9.3.5 + resolution: "glob@npm:9.3.5" + dependencies: + fs.realpath: ^1.0.0 + minimatch: ^8.0.2 + minipass: ^4.2.4 + path-scurry: ^1.6.1 + checksum: 94b093adbc591bc36b582f77927d1fb0dbf3ccc231828512b017601408be98d1fe798fc8c0b19c6f2d1a7660339c3502ce698de475e9d938ccbb69b47b647c84 + languageName: node + linkType: hard + +"global-modules@npm:^2.0.0": + version: 2.0.0 + resolution: "global-modules@npm:2.0.0" + dependencies: + global-prefix: ^3.0.0 + checksum: d6197f25856c878c2fb5f038899f2dca7cbb2f7b7cf8999660c0104972d5cfa5c68b5a0a77fa8206bb536c3903a4615665acb9709b4d80846e1bb47eaef65430 + languageName: node + linkType: hard + +"global-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "global-prefix@npm:3.0.0" + dependencies: + ini: ^1.3.5 + kind-of: ^6.0.2 + which: ^1.3.1 + checksum: 8a82fc1d6f22c45484a4e34656cc91bf021a03e03213b0035098d605bfc612d7141f1e14a21097e8a0413b4884afd5b260df0b6a25605ce9d722e11f1df2881d + languageName: node + linkType: hard + +"globals@npm:^11.1.0": + version: 11.12.0 + resolution: "globals@npm:11.12.0" + checksum: 67051a45eca3db904aee189dfc7cd53c20c7d881679c93f6146ddd4c9f4ab2268e68a919df740d39c71f4445d2b38ee360fc234428baea1dbdfe68bbcb46979e + languageName: node + linkType: hard + +"globals@npm:^13.19.0": + version: 13.20.0 + resolution: "globals@npm:13.20.0" + dependencies: + type-fest: ^0.20.2 + checksum: ad1ecf914bd051325faad281d02ea2c0b1df5d01bd94d368dcc5513340eac41d14b3c61af325768e3c7f8d44576e72780ec0b6f2d366121f8eec6e03c3a3b97a + languageName: node + linkType: hard + +"globalthis@npm:^1.0.3": + version: 1.0.3 + resolution: "globalthis@npm:1.0.3" + dependencies: + define-properties: ^1.1.3 + checksum: fbd7d760dc464c886d0196166d92e5ffb4c84d0730846d6621a39fbbc068aeeb9c8d1421ad330e94b7bca4bb4ea092f5f21f3d36077812af5d098b4dc006c998 + languageName: node + linkType: hard + +"globby@npm:10.0.0": + version: 10.0.0 + resolution: "globby@npm:10.0.0" + dependencies: + "@types/glob": ^7.1.1 + array-union: ^2.1.0 + dir-glob: ^3.0.1 + fast-glob: ^3.0.3 + glob: ^7.1.3 + ignore: ^5.1.1 + merge2: ^1.2.3 + slash: ^3.0.0 + checksum: fbff58d2fcaedd9207901f6e3b5341ff885b6d499c3a095f7befde0fd03ec1ea634452a82f81e894e46f6a5d704da44b842ba93066f90dced52adf84d4b8d1cc + languageName: node + linkType: hard + +"globby@npm:11.1.0, globby@npm:^11.0.1, globby@npm:^11.1.0": + version: 11.1.0 + resolution: "globby@npm:11.1.0" + dependencies: + array-union: ^2.1.0 + dir-glob: ^3.0.1 + fast-glob: ^3.2.9 + ignore: ^5.2.0 + merge2: ^1.4.1 + slash: ^3.0.0 + checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 + languageName: node + linkType: hard + +"globby@npm:^13.1.1": + version: 13.1.3 + resolution: "globby@npm:13.1.3" + dependencies: + dir-glob: ^3.0.1 + fast-glob: ^3.2.11 + ignore: ^5.2.0 + merge2: ^1.4.1 + slash: ^4.0.0 + checksum: 93f06e02002cdf368f7e3d55bd59e7b00784c7cc8fe92c7ee5082cc7171ff6109fda45e1c97a80bb48bc811dedaf7843c7c9186f5f84bde4883ab630e13c43df + languageName: node + linkType: hard + +"globjoin@npm:^0.1.4": + version: 0.1.4 + resolution: "globjoin@npm:0.1.4" + checksum: 0a47d88d566122d9e42da946453ee38b398e0021515ac6a95d13f980ba8c1e42954e05ee26cfcbffce1ac1ee094d0524b16ce1dd874ca52408d6db5c6d39985b + languageName: node + linkType: hard + +"gopd@npm:^1.0.1": + version: 1.0.1 + resolution: "gopd@npm:1.0.1" + dependencies: + get-intrinsic: ^1.1.3 + checksum: a5ccfb8806e0917a94e0b3de2af2ea4979c1da920bc381667c260e00e7cafdbe844e2cb9c5bcfef4e5412e8bf73bab837285bc35c7ba73aaaf0134d4583393a6 + languageName: node + linkType: hard + +"got@npm:^11.7.0, got@npm:^11.8.2": + version: 11.8.6 + resolution: "got@npm:11.8.6" + dependencies: + "@sindresorhus/is": ^4.0.0 + "@szmarczak/http-timer": ^4.0.5 + "@types/cacheable-request": ^6.0.1 + "@types/responselike": ^1.0.0 + cacheable-lookup: ^5.0.3 + cacheable-request: ^7.0.2 + decompress-response: ^6.0.0 + http2-wrapper: ^1.0.0-beta.5.2 + lowercase-keys: ^2.0.0 + p-cancelable: ^2.0.0 + responselike: ^2.0.0 + checksum: bbc783578a8d5030c8164ef7f57ce41b5ad7db2ed13371e1944bef157eeca5a7475530e07c0aaa71610d7085474d0d96222c9f4268d41db333a17e39b463f45d + languageName: node + linkType: hard + +"graceful-fs@npm:4.2.11, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 + languageName: node + linkType: hard + +"grapheme-splitter@npm:^1.0.4": + version: 1.0.4 + resolution: "grapheme-splitter@npm:1.0.4" + checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 + languageName: node + linkType: hard + +"gzip-size@npm:^6.0.0": + version: 6.0.0 + resolution: "gzip-size@npm:6.0.0" + dependencies: + duplexer: ^0.1.2 + checksum: 2df97f359696ad154fc171dcb55bc883fe6e833bca7a65e457b9358f3cb6312405ed70a8da24a77c1baac0639906cd52358dc0ce2ec1a937eaa631b934c94194 + languageName: node + linkType: hard + +"handlebars@npm:4.7.7, handlebars@npm:^4.5.3, handlebars@npm:^4.7.7": + version: 4.7.7 + resolution: "handlebars@npm:4.7.7" + dependencies: + minimist: ^1.2.5 + neo-async: ^2.6.0 + source-map: ^0.6.1 + uglify-js: ^3.1.4 + wordwrap: ^1.0.0 + dependenciesMeta: + uglify-js: + optional: true + bin: + handlebars: bin/handlebars + checksum: 1e79a43f5e18d15742977cb987923eab3e2a8f44f2d9d340982bcb69e1735ed049226e534d7c1074eaddaf37e4fb4f471a8adb71cddd5bc8cf3f894241df5cee + languageName: node + linkType: hard + +"har-schema@npm:^2.0.0": + version: 2.0.0 + resolution: "har-schema@npm:2.0.0" + checksum: d8946348f333fb09e2bf24cc4c67eabb47c8e1d1aa1c14184c7ffec1140a49ec8aa78aa93677ae452d71d5fc0fdeec20f0c8c1237291fc2bcb3f502a5d204f9b + languageName: node + linkType: hard + +"har-validator@npm:~5.1.3": + version: 5.1.5 + resolution: "har-validator@npm:5.1.5" + dependencies: + ajv: ^6.12.3 + har-schema: ^2.0.0 + checksum: b998a7269ca560d7f219eedc53e2c664cd87d487e428ae854a6af4573fc94f182fe9d2e3b92ab968249baec7ebaf9ead69cf975c931dc2ab282ec182ee988280 + languageName: node + linkType: hard + +"hard-rejection@npm:^2.1.0": + version: 2.1.0 + resolution: "hard-rejection@npm:2.1.0" + checksum: 7baaf80a0c7fff4ca79687b4060113f1529589852152fa935e6787a2bc96211e784ad4588fb3048136ff8ffc9dfcf3ae385314a5b24db32de20bea0d1597f9dc + languageName: node + linkType: hard + +"harmony-reflect@npm:^1.4.6": + version: 1.6.2 + resolution: "harmony-reflect@npm:1.6.2" + checksum: 2e5bae414cd2bfae5476147f9935dc69ee9b9a413206994dcb94c5b3208d4555da3d4313aff6fd14bd9991c1e3ef69cdda5c8fac1eb1d7afc064925839339b8c + languageName: node + linkType: hard + +"has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": + version: 1.0.2 + resolution: "has-bigints@npm:1.0.2" + checksum: 390e31e7be7e5c6fe68b81babb73dfc35d413604d7ee5f56da101417027a4b4ce6a27e46eff97ad040c835b5d228676eae99a9b5c3bc0e23c8e81a49241ff45b + languageName: node + linkType: hard + +"has-flag@npm:^3.0.0": + version: 3.0.0 + resolution: "has-flag@npm:3.0.0" + checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad + languageName: node + linkType: hard + +"has-property-descriptors@npm:^1.0.0": + version: 1.0.0 + resolution: "has-property-descriptors@npm:1.0.0" + dependencies: + get-intrinsic: ^1.1.1 + checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb + languageName: node + linkType: hard + +"has-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "has-proto@npm:1.0.1" + checksum: febc5b5b531de8022806ad7407935e2135f1cc9e64636c3916c6842bd7995994ca3b29871ecd7954bd35f9e2986c17b3b227880484d22259e2f8e6ce63fd383e + languageName: node + linkType: hard + +"has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3": + version: 1.0.3 + resolution: "has-symbols@npm:1.0.3" + checksum: a054c40c631c0d5741a8285010a0777ea0c068f99ed43e5d6eb12972da223f8af553a455132fdb0801bdcfa0e0f443c0c03a68d8555aa529b3144b446c3f2410 + languageName: node + linkType: hard + +"has-tostringtag@npm:^1.0.0": + version: 1.0.0 + resolution: "has-tostringtag@npm:1.0.0" + dependencies: + has-symbols: ^1.0.2 + checksum: cc12eb28cb6ae22369ebaad3a8ab0799ed61270991be88f208d508076a1e99abe4198c965935ce85ea90b60c94ddda73693b0920b58e7ead048b4a391b502c1c + languageName: node + linkType: hard + +"has-unicode@npm:2.0.1, has-unicode@npm:^2.0.1": + version: 2.0.1 + resolution: "has-unicode@npm:2.0.1" + checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 + languageName: node + linkType: hard + +"has@npm:^1.0.3": + version: 1.0.3 + resolution: "has@npm:1.0.3" + dependencies: + function-bind: ^1.1.1 + checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792 + languageName: node + linkType: hard + +"he@npm:^1.2.0": + version: 1.2.0 + resolution: "he@npm:1.2.0" + bin: + he: bin/he + checksum: 3d4d6babccccd79c5c5a3f929a68af33360d6445587d628087f39a965079d84f18ce9c3d3f917ee1e3978916fc833bb8b29377c3b403f919426f91bc6965e7a7 + languageName: node + linkType: hard + +"highlight-words-core@npm:^1.2.0": + version: 1.2.2 + resolution: "highlight-words-core@npm:1.2.2" + checksum: 737758a8a572c82919552b031df300016164b7d0db6a819d24bc6c7ca2279d3cd6d03497728930d6402423c7a3fc2f42c628a9b01b025c704a0b56a635377511 + languageName: node + linkType: hard + +"hosted-git-info@npm:^2.1.4": + version: 2.8.9 + resolution: "hosted-git-info@npm:2.8.9" + checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd + languageName: node + linkType: hard + +"hosted-git-info@npm:^3.0.6": + version: 3.0.8 + resolution: "hosted-git-info@npm:3.0.8" + dependencies: + lru-cache: ^6.0.0 + checksum: 5af7a69581acb84206a7b8e009f4680c36396814e92c8a83973dfb3b87e44e44d1f7b8eaf3e4a953686482770ecb78406a4ce4666bfdfe447762434127871d8d + languageName: node + linkType: hard + +"hosted-git-info@npm:^4.0.0, hosted-git-info@npm:^4.0.1": + version: 4.1.0 + resolution: "hosted-git-info@npm:4.1.0" + dependencies: + lru-cache: ^6.0.0 + checksum: c3f87b3c2f7eb8c2748c8f49c0c2517c9a95f35d26f4bf54b2a8cba05d2e668f3753548b6ea366b18ec8dadb4e12066e19fa382a01496b0ffa0497eb23cbe461 + languageName: node + linkType: hard + +"hosted-git-info@npm:^6.0.0": + version: 6.1.1 + resolution: "hosted-git-info@npm:6.1.1" + dependencies: + lru-cache: ^7.5.1 + checksum: fcd3ca2eaa05f3201425ccbb8aa47f88cdda4a3a6d79453f8e269f7171356278bd1db08f059d8439eb5eaa91c6a8a20800fc49cca6e9e4e899b202a332d5ba6b + languageName: node + linkType: hard + +"html-encoding-sniffer@npm:^3.0.0": + version: 3.0.0 + resolution: "html-encoding-sniffer@npm:3.0.0" + dependencies: + whatwg-encoding: ^2.0.0 + checksum: 8d806aa00487e279e5ccb573366a951a9f68f65c90298eac9c3a2b440a7ffe46615aff2995a2f61c6746c639234e6179a97e18ca5ccbbf93d3725ef2099a4502 + languageName: node + linkType: hard + +"html-escaper@npm:^2.0.0": + version: 2.0.2 + resolution: "html-escaper@npm:2.0.2" + checksum: d2df2da3ad40ca9ee3a39c5cc6475ef67c8f83c234475f24d8e9ce0dc80a2c82df8e1d6fa78ddd1e9022a586ea1bd247a615e80a5cd9273d90111ddda7d9e974 + languageName: node + linkType: hard + +"html-loader@npm:~1.3.0": + version: 1.3.2 + resolution: "html-loader@npm:1.3.2" + dependencies: + html-minifier-terser: ^5.1.1 + htmlparser2: ^4.1.0 + loader-utils: ^2.0.0 + schema-utils: ^3.0.0 + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: 51da7c05e41ee0bdd5c43ca5b9d87e2a69750617503c4333e3e9aa0ca5778f0cc45462e7f5ee1098f319c19782d8b2d7588bf4be66ea0fff7046e54aee47b00b + languageName: node + linkType: hard + +"html-minifier-terser@npm:^5.1.1": + version: 5.1.1 + resolution: "html-minifier-terser@npm:5.1.1" + dependencies: + camel-case: ^4.1.1 + clean-css: ^4.2.3 + commander: ^4.1.1 + he: ^1.2.0 + param-case: ^3.0.3 + relateurl: ^0.2.7 + terser: ^4.6.3 + bin: + html-minifier-terser: cli.js + checksum: 75ff3ff886631b9ecb3035acb8e7dd98c599bb4d4618ad6f7e487ee9752987dddcf6848dc3c1ab1d7fc1ad4484337c2ce39c19eac17b0342b4b15e4294c8a904 + languageName: node + linkType: hard + +"html-minifier-terser@npm:^6.0.2": + version: 6.1.0 + resolution: "html-minifier-terser@npm:6.1.0" + dependencies: + camel-case: ^4.1.2 + clean-css: ^5.2.2 + commander: ^8.3.0 + he: ^1.2.0 + param-case: ^3.0.4 + relateurl: ^0.2.7 + terser: ^5.10.0 + bin: + html-minifier-terser: cli.js + checksum: ac52c14006476f773204c198b64838477859dc2879490040efab8979c0207424da55d59df7348153f412efa45a0840a1ca3c757bf14767d23a15e3e389d37a93 + languageName: node + linkType: hard + +"html-tags@npm:^3.3.1": + version: 3.3.1 + resolution: "html-tags@npm:3.3.1" + checksum: b4ef1d5a76b678e43cce46e3783d563607b1d550cab30b4f511211564574770aa8c658a400b100e588bc60b8234e59b35ff72c7851cc28f3b5403b13a2c6cbce + languageName: node + linkType: hard + +"html-webpack-plugin@npm:^5.5.0": + version: 5.5.0 + resolution: "html-webpack-plugin@npm:5.5.0" + dependencies: + "@types/html-minifier-terser": ^6.0.0 + html-minifier-terser: ^6.0.2 + lodash: ^4.17.21 + pretty-error: ^4.0.0 + tapable: ^2.0.0 + peerDependencies: + webpack: ^5.20.0 + checksum: f3d84d0df71fe2f5bac533cc74dce41ab058558cdcc6ff767d166a2abf1cf6fb8491d54d60ddbb34e95c00394e379ba52e0468e0284d1d0cc6a42987056e8219 + languageName: node + linkType: hard + +"htmlparser2@npm:^4.1.0": + version: 4.1.0 + resolution: "htmlparser2@npm:4.1.0" + dependencies: + domelementtype: ^2.0.1 + domhandler: ^3.0.0 + domutils: ^2.0.0 + entities: ^2.0.0 + checksum: 615fcf34ae74775eba9d2c7c54034201645ac4146dfe2889cda21939aa77806ad3aee27963ae72c5c2da23ce7b0b99b2533e1d9f327b74821cc11f755cc5153f + languageName: node + linkType: hard + +"htmlparser2@npm:^6.0.0, htmlparser2@npm:^6.1.0": + version: 6.1.0 + resolution: "htmlparser2@npm:6.1.0" + dependencies: + domelementtype: ^2.0.1 + domhandler: ^4.0.0 + domutils: ^2.5.2 + entities: ^2.0.0 + checksum: 81a7b3d9c3bb9acb568a02fc9b1b81ffbfa55eae7f1c41ae0bf840006d1dbf54cb3aa245b2553e2c94db674840a9f0fdad7027c9a9d01a062065314039058c4e + languageName: node + linkType: hard + +"htmlparser2@npm:^8.0.0": + version: 8.0.1 + resolution: "htmlparser2@npm:8.0.1" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.2 + domutils: ^3.0.1 + entities: ^4.3.0 + checksum: 06d5c71e8313597722bc429ae2a7a8333d77bd3ab07ccb916628384b37332027b047f8619448d8f4a3312b6609c6ea3302a4e77435d859e9e686999e6699ca39 + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.0, http-cache-semantics@npm:^4.1.1": + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 + languageName: node + linkType: hard + +"http-errors@npm:2.0.0": + version: 2.0.0 + resolution: "http-errors@npm:2.0.0" + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + checksum: 9b0a3782665c52ce9dc658a0d1560bcb0214ba5699e4ea15aefb2a496e2ca83db03ebc42e1cce4ac1f413e4e0d2d736a3fd755772c556a9a06853ba2a0b7d920 + languageName: node + linkType: hard + +"http-proxy-agent@npm:^5.0.0": + version: 5.0.0 + resolution: "http-proxy-agent@npm:5.0.0" + dependencies: + "@tootallnate/once": 2 + agent-base: 6 + debug: 4 + checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 + languageName: node + linkType: hard + +"http-signature@npm:~1.2.0": + version: 1.2.0 + resolution: "http-signature@npm:1.2.0" + dependencies: + assert-plus: ^1.0.0 + jsprim: ^1.2.2 + sshpk: ^1.7.0 + checksum: 3324598712266a9683585bb84a75dec4fd550567d5e0dd4a0fff6ff3f74348793404d3eeac4918fa0902c810eeee1a86419e4a2e92a164132dfe6b26743fb47c + languageName: node + linkType: hard + +"http-status-codes@npm:2.2.0": + version: 2.2.0 + resolution: "http-status-codes@npm:2.2.0" + checksum: 31e1d730856210445da0907d9b484629e69e4fe92ac032478a7aa4d89e5b215e2b4e75d7ebce40d0537b6850bd281b2f65c7cc36cc2677e5de056d6cea1045ce + languageName: node + linkType: hard + +"http2-wrapper@npm:^1.0.0-beta.5.2": + version: 1.0.3 + resolution: "http2-wrapper@npm:1.0.3" + dependencies: + quick-lru: ^5.1.1 + resolve-alpn: ^1.0.0 + checksum: 74160b862ec699e3f859739101ff592d52ce1cb207b7950295bf7962e4aa1597ef709b4292c673bece9c9b300efad0559fc86c71b1409c7a1e02b7229456003e + languageName: node + linkType: hard + +"https-proxy-agent@npm:5.0.1, https-proxy-agent@npm:^5.0.0, https-proxy-agent@npm:^5.0.1": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: 6 + debug: 4 + checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 + languageName: node + linkType: hard + +"human-signals@npm:^2.1.0": + version: 2.1.0 + resolution: "human-signals@npm:2.1.0" + checksum: b87fd89fce72391625271454e70f67fe405277415b48bcc0117ca73d31fa23a4241787afdc8d67f5a116cf37258c052f59ea82daffa72364d61351423848e3b8 + languageName: node + linkType: hard + +"human-signals@npm:^4.3.0": + version: 4.3.1 + resolution: "human-signals@npm:4.3.1" + checksum: 6f12958df3f21b6fdaf02d90896c271df00636a31e2bbea05bddf817a35c66b38a6fdac5863e2df85bd52f34958997f1f50350ff97249e1dff8452865d5235d1 + languageName: node + linkType: hard + +"humanize-ms@npm:^1.2.1": + version: 1.2.1 + resolution: "humanize-ms@npm:1.2.1" + dependencies: + ms: ^2.0.0 + checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 + languageName: node + linkType: hard + +"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24": + version: 0.4.24 + resolution: "iconv-lite@npm:0.4.24" + dependencies: + safer-buffer: ">= 2.1.2 < 3" + checksum: bd9f120f5a5b306f0bc0b9ae1edeb1577161503f5f8252a20f1a9e56ef8775c9959fd01c55f2d3a39d9a8abaf3e30c1abeb1895f367dcbbe0a8fd1c9ca01c4f6 + languageName: node + linkType: hard + +"iconv-lite@npm:0.6, iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: ">= 2.1.2 < 3.0.0" + checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf + languageName: node + linkType: hard + +"icss-utils@npm:^5.0.0, icss-utils@npm:^5.1.0": + version: 5.1.0 + resolution: "icss-utils@npm:5.1.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 5c324d283552b1269cfc13a503aaaa172a280f914e5b81544f3803bc6f06a3b585fb79f66f7c771a2c052db7982c18bf92d001e3b47282e3abbbb4c4cc488d68 + languageName: node + linkType: hard + +"identity-obj-proxy@npm:^3.0.0": + version: 3.0.0 + resolution: "identity-obj-proxy@npm:3.0.0" + dependencies: + harmony-reflect: ^1.4.6 + checksum: 97559f8ea2aeaa1a880d279d8c49550dce01148321e00a2102cda5ddf9ce622fa1d7f3efc7bed63458af78889de888fdaebaf31c816312298bb3fdd0ef8aaf2c + languageName: node + linkType: hard + +"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e + languageName: node + linkType: hard + +"ignore-walk@npm:^5.0.1": + version: 5.0.1 + resolution: "ignore-walk@npm:5.0.1" + dependencies: + minimatch: ^5.0.1 + checksum: 1a4ef35174653a1aa6faab3d9f8781269166536aee36a04946f6e2b319b2475c1903a75ed42f04219274128242f49d0a10e20c4354ee60d9548e97031451150b + languageName: node + linkType: hard + +"ignore-walk@npm:^6.0.0": + version: 6.0.3 + resolution: "ignore-walk@npm:6.0.3" + dependencies: + minimatch: ^9.0.0 + checksum: d8ba534beb3a3fa48ddd32c79bbedb14a831ff7fab548674765d661d8f8d0df4b0827e3ad86e35cb15ff027655bfd6a477bd8d5d0411e229975a7c716f1fc9de + languageName: node + linkType: hard + +"ignore@npm:^5.0.4, ignore@npm:^5.1.1, ignore@npm:^5.2.0, ignore@npm:^5.2.4": + version: 5.2.4 + resolution: "ignore@npm:5.2.4" + checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef + languageName: node + linkType: hard + +"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1": + version: 3.3.0 + resolution: "import-fresh@npm:3.3.0" + dependencies: + parent-module: ^1.0.0 + resolve-from: ^4.0.0 + checksum: 2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa + languageName: node + linkType: hard + +"import-lazy@npm:^4.0.0": + version: 4.0.0 + resolution: "import-lazy@npm:4.0.0" + checksum: 22f5e51702134aef78890156738454f620e5fe7044b204ebc057c614888a1dd6fdf2ede0fdcca44d5c173fd64f65c985f19a51775b06967ef58cc3d26898df07 + languageName: node + linkType: hard + +"import-local@npm:3.1.0, import-local@npm:^3.0.2": + version: 3.1.0 + resolution: "import-local@npm:3.1.0" + dependencies: + pkg-dir: ^4.2.0 + resolve-cwd: ^3.0.0 + bin: + import-local-fixture: fixtures/cli.js + checksum: bfcdb63b5e3c0e245e347f3107564035b128a414c4da1172a20dc67db2504e05ede4ac2eee1252359f78b0bfd7b19ef180aec427c2fce6493ae782d73a04cddd + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 + languageName: node + linkType: hard + +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 + languageName: node + linkType: hard + +"indent-string@npm:^5.0.0": + version: 5.0.0 + resolution: "indent-string@npm:5.0.0" + checksum: e466c27b6373440e6d84fbc19e750219ce25865cb82d578e41a6053d727e5520dc5725217d6eb1cc76005a1bb1696a0f106d84ce7ebda3033b963a38583fb3b3 + languageName: node + linkType: hard + +"infer-owner@npm:^1.0.4": + version: 1.0.4 + resolution: "infer-owner@npm:1.0.4" + checksum: 181e732764e4a0611576466b4b87dac338972b839920b2a8cde43642e4ed6bd54dc1fb0b40874728f2a2df9a1b097b8ff83b56d5f8f8e3927f837fdcb47d8a89 + languageName: node + linkType: hard + +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" + dependencies: + once: ^1.3.0 + wrappy: 1 + checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd + languageName: node + linkType: hard + +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 + languageName: node + linkType: hard + +"inherits@npm:2.0.3": + version: 2.0.3 + resolution: "inherits@npm:2.0.3" + checksum: 78cb8d7d850d20a5e9a7f3620db31483aa00ad5f722ce03a55b110e5a723539b3716a3b463e2b96ce3fe286f33afc7c131fa2f91407528ba80cea98a7545d4c0 + languageName: node + linkType: hard + +"ini@npm:^1.3.2, ini@npm:^1.3.5, ini@npm:^1.3.8, ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: dfd98b0ca3a4fc1e323e38a6c8eb8936e31a97a918d3b377649ea15bdb15d481207a0dda1021efbd86b464cae29a0d33c1d7dcaf6c5672bee17fa849bc50a1b3 + languageName: node + linkType: hard + +"init-package-json@npm:5.0.0": + version: 5.0.0 + resolution: "init-package-json@npm:5.0.0" + dependencies: + npm-package-arg: ^10.0.0 + promzard: ^1.0.0 + read: ^2.0.0 + read-package-json: ^6.0.0 + semver: ^7.3.5 + validate-npm-package-license: ^3.0.4 + validate-npm-package-name: ^5.0.0 + checksum: ad601c717d5ea3ff5a416cbe7d39417bb3914596dce7a386bffe856229435ebef06eb600736326effdd4e57a02d41164aa525d31d51ec49812c8e8c215d1d7c8 + languageName: node + linkType: hard + +"inquirer@npm:^8.2.4": + version: 8.2.5 + resolution: "inquirer@npm:8.2.5" + dependencies: + ansi-escapes: ^4.2.1 + chalk: ^4.1.1 + cli-cursor: ^3.1.0 + cli-width: ^3.0.0 + external-editor: ^3.0.3 + figures: ^3.0.0 + lodash: ^4.17.21 + mute-stream: 0.0.8 + ora: ^5.4.1 + run-async: ^2.4.0 + rxjs: ^7.5.5 + string-width: ^4.1.0 + strip-ansi: ^6.0.0 + through: ^2.3.6 + wrap-ansi: ^7.0.0 + checksum: f13ee4c444187786fb393609dedf6b30870115a57b603f2e6424f29a99abc13446fd45ee22461c33c9c40a92a60a8df62d0d6b25d74fc6676fa4cb211de55b55 + languageName: node + linkType: hard + +"inquirer@npm:^9.1.4": + version: 9.1.4 + resolution: "inquirer@npm:9.1.4" + dependencies: + ansi-escapes: ^6.0.0 + chalk: ^5.1.2 + cli-cursor: ^4.0.0 + cli-width: ^4.0.0 + external-editor: ^3.0.3 + figures: ^5.0.0 + lodash: ^4.17.21 + mute-stream: 0.0.8 + ora: ^6.1.2 + run-async: ^2.4.0 + rxjs: ^7.5.7 + string-width: ^5.1.2 + strip-ansi: ^7.0.1 + through: ^2.3.6 + wrap-ansi: ^8.0.1 + checksum: b9acb56dfc01fdc3aac5997260b9c88b84893e270254cb67a8bef8d074d2deeea500963e69247510f1790a6b656b0a11e981441d084ce6d906e7e2a7c5441aa2 + languageName: node + linkType: hard + +"internal-slot@npm:^1.0.3, internal-slot@npm:^1.0.4": + version: 1.0.5 + resolution: "internal-slot@npm:1.0.5" + dependencies: + get-intrinsic: ^1.2.0 + has: ^1.0.3 + side-channel: ^1.0.4 + checksum: 97e84046bf9e7574d0956bd98d7162313ce7057883b6db6c5c7b5e5f05688864b0978ba07610c726d15d66544ffe4b1050107d93f8a39ebc59b15d8b429b497a + languageName: node + linkType: hard + +"internmap@npm:1 - 2": + version: 2.0.3 + resolution: "internmap@npm:2.0.3" + checksum: 7ca41ec6aba8f0072fc32fa8a023450a9f44503e2d8e403583c55714b25efd6390c38a87161ec456bf42d7bc83aab62eb28f5aef34876b1ac4e60693d5e1d241 + languageName: node + linkType: hard + +"interpret@npm:^3.1.1": + version: 3.1.1 + resolution: "interpret@npm:3.1.1" + checksum: 35cebcf48c7351130437596d9ab8c8fe131ce4038da4561e6d665f25640e0034702a031cf7e3a5cea60ac7ac548bf17465e0571ede126f3d3a6933152171ac82 + languageName: node + linkType: hard + +"ip@npm:^2.0.0": + version: 2.0.0 + resolution: "ip@npm:2.0.0" + checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 + languageName: node + linkType: hard + +"ipaddr.js@npm:1.9.1": + version: 1.9.1 + resolution: "ipaddr.js@npm:1.9.1" + checksum: f88d3825981486f5a1942414c8d77dd6674dd71c065adcfa46f578d677edcb99fda25af42675cb59db492fdf427b34a5abfcde3982da11a8fd83a500b41cfe77 + languageName: node + linkType: hard + +"is-array-buffer@npm:^3.0.1": + version: 3.0.2 + resolution: "is-array-buffer@npm:3.0.2" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.2.0 + is-typed-array: ^1.1.10 + checksum: dcac9dda66ff17df9cabdc58214172bf41082f956eab30bb0d86bc0fab1e44b690fc8e1f855cf2481245caf4e8a5a006a982a71ddccec84032ed41f9d8da8c14 + languageName: node + linkType: hard + +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: eef4417e3c10e60e2c810b6084942b3ead455af16c4509959a27e490e7aee87cfb3f38e01bbde92220b528a0ee1a18d52b787e1458ee86174d8c7f0e58cd488f + languageName: node + linkType: hard + +"is-arrayish@npm:^0.3.1": + version: 0.3.2 + resolution: "is-arrayish@npm:0.3.2" + checksum: 977e64f54d91c8f169b59afcd80ff19227e9f5c791fa28fa2e5bce355cbaf6c2c356711b734656e80c9dd4a854dd7efcf7894402f1031dfc5de5d620775b4d5f + languageName: node + linkType: hard + +"is-bigint@npm:^1.0.1": + version: 1.0.4 + resolution: "is-bigint@npm:1.0.4" + dependencies: + has-bigints: ^1.0.1 + checksum: c56edfe09b1154f8668e53ebe8252b6f185ee852a50f9b41e8d921cb2bed425652049fbe438723f6cb48a63ca1aa051e948e7e401e093477c99c84eba244f666 + languageName: node + linkType: hard + +"is-binary-path@npm:~2.1.0": + version: 2.1.0 + resolution: "is-binary-path@npm:2.1.0" + dependencies: + binary-extensions: ^2.0.0 + checksum: 84192eb88cff70d320426f35ecd63c3d6d495da9d805b19bc65b518984b7c0760280e57dbf119b7e9be6b161784a5a673ab2c6abe83abb5198a432232ad5b35c + languageName: node + linkType: hard + +"is-boolean-object@npm:^1.1.0": + version: 1.1.2 + resolution: "is-boolean-object@npm:1.1.2" + dependencies: + call-bind: ^1.0.2 + has-tostringtag: ^1.0.0 + checksum: c03b23dbaacadc18940defb12c1c0e3aaece7553ef58b162a0f6bba0c2a7e1551b59f365b91e00d2dbac0522392d576ef322628cb1d036a0fe51eb466db67222 + languageName: node + linkType: hard + +"is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.1.5, is-callable@npm:^1.2.7": + version: 1.2.7 + resolution: "is-callable@npm:1.2.7" + checksum: 61fd57d03b0d984e2ed3720fb1c7a897827ea174bd44402878e059542ea8c4aeedee0ea0985998aa5cc2736b2fa6e271c08587addb5b3959ac52cf665173d1ac + languageName: node + linkType: hard + +"is-ci@npm:3.0.1": + version: 3.0.1 + resolution: "is-ci@npm:3.0.1" + dependencies: + ci-info: ^3.2.0 + bin: + is-ci: bin.js + checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e + languageName: node + linkType: hard + +"is-core-module@npm:^2.5.0, is-core-module@npm:^2.8.1, is-core-module@npm:^2.9.0": + version: 2.11.0 + resolution: "is-core-module@npm:2.11.0" + dependencies: + has: ^1.0.3 + checksum: f96fd490c6b48eb4f6d10ba815c6ef13f410b0ba6f7eb8577af51697de523e5f2cd9de1c441b51d27251bf0e4aebc936545e33a5d26d5d51f28d25698d4a8bab + languageName: node + linkType: hard + +"is-date-object@npm:^1.0.1": + version: 1.0.5 + resolution: "is-date-object@npm:1.0.5" + dependencies: + has-tostringtag: ^1.0.0 + checksum: baa9077cdf15eb7b58c79398604ca57379b2fc4cf9aa7a9b9e295278648f628c9b201400c01c5e0f7afae56507d741185730307cbe7cad3b9f90a77e5ee342fc + languageName: node + linkType: hard + +"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": + version: 2.2.1 + resolution: "is-docker@npm:2.2.1" + bin: + is-docker: cli.js + checksum: 3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 + languageName: node + linkType: hard + +"is-docker@npm:^3.0.0": + version: 3.0.0 + resolution: "is-docker@npm:3.0.0" + bin: + is-docker: cli.js + checksum: b698118f04feb7eaf3338922bd79cba064ea54a1c3db6ec8c0c8d8ee7613e7e5854d802d3ef646812a8a3ace81182a085dfa0a71cc68b06f3fa794b9783b3c90 + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 + languageName: node + linkType: hard + +"is-generator-fn@npm:^2.0.0": + version: 2.1.0 + resolution: "is-generator-fn@npm:2.1.0" + checksum: a6ad5492cf9d1746f73b6744e0c43c0020510b59d56ddcb78a91cbc173f09b5e6beff53d75c9c5a29feb618bfef2bf458e025ecf3a57ad2268e2fb2569f56215 + languageName: node + linkType: hard + +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: ^2.1.1 + checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 + languageName: node + linkType: hard + +"is-inside-container@npm:^1.0.0": + version: 1.0.0 + resolution: "is-inside-container@npm:1.0.0" + dependencies: + is-docker: ^3.0.0 + bin: + is-inside-container: cli.js + checksum: c50b75a2ab66ab3e8b92b3bc534e1ea72ca25766832c0623ac22d134116a98bcf012197d1caabe1d1c4bd5f84363d4aa5c36bb4b585fbcaf57be172cd10a1a03 + languageName: node + linkType: hard + +"is-interactive@npm:^1.0.0": + version: 1.0.0 + resolution: "is-interactive@npm:1.0.0" + checksum: 824808776e2d468b2916cdd6c16acacebce060d844c35ca6d82267da692e92c3a16fdba624c50b54a63f38bdc4016055b6f443ce57d7147240de4f8cdabaf6f9 + languageName: node + linkType: hard + +"is-interactive@npm:^2.0.0": + version: 2.0.0 + resolution: "is-interactive@npm:2.0.0" + checksum: e8d52ad490bed7ae665032c7675ec07732bbfe25808b0efbc4d5a76b1a1f01c165f332775c63e25e9a03d319ebb6b24f571a9e902669fc1e40b0a60b5be6e26c + languageName: node + linkType: hard + +"is-lambda@npm:^1.0.1": + version: 1.0.1 + resolution: "is-lambda@npm:1.0.1" + checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 + languageName: node + linkType: hard + +"is-negative-zero@npm:^2.0.2": + version: 2.0.2 + resolution: "is-negative-zero@npm:2.0.2" + checksum: f3232194c47a549da60c3d509c9a09be442507616b69454716692e37ae9f37c4dea264fb208ad0c9f3efd15a796a46b79df07c7e53c6227c32170608b809149a + languageName: node + linkType: hard + +"is-number-object@npm:^1.0.4": + version: 1.0.7 + resolution: "is-number-object@npm:1.0.7" + dependencies: + has-tostringtag: ^1.0.0 + checksum: d1e8d01bb0a7134c74649c4e62da0c6118a0bfc6771ea3c560914d52a627873e6920dd0fd0ebc0e12ad2ff4687eac4c308f7e80320b973b2c8a2c8f97a7524f7 + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a + languageName: node + linkType: hard + +"is-obj@npm:^2.0.0": + version: 2.0.0 + resolution: "is-obj@npm:2.0.0" + checksum: c9916ac8f4621962a42f5e80e7ffdb1d79a3fab7456ceaeea394cd9e0858d04f985a9ace45be44433bf605673c8be8810540fe4cc7f4266fc7526ced95af5a08 + languageName: node + linkType: hard + +"is-path-inside@npm:^3.0.3": + version: 3.0.3 + resolution: "is-path-inside@npm:3.0.3" + checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 + languageName: node + linkType: hard + +"is-plain-obj@npm:2.1.0": + version: 2.1.0 + resolution: "is-plain-obj@npm:2.1.0" + checksum: cec9100678b0a9fe0248a81743041ed990c2d4c99f893d935545cfbc42876cbe86d207f3b895700c690ad2fa520e568c44afc1605044b535a7820c1d40e38daa + languageName: node + linkType: hard + +"is-plain-obj@npm:^1.0.0, is-plain-obj@npm:^1.1.0": + version: 1.1.0 + resolution: "is-plain-obj@npm:1.1.0" + checksum: 0ee04807797aad50859652a7467481816cbb57e5cc97d813a7dcd8915da8195dc68c436010bf39d195226cde6a2d352f4b815f16f26b7bf486a5754290629931 + languageName: node + linkType: hard + +"is-plain-object@npm:^2.0.4": + version: 2.0.4 + resolution: "is-plain-object@npm:2.0.4" + dependencies: + isobject: ^3.0.1 + checksum: 2a401140cfd86cabe25214956ae2cfee6fbd8186809555cd0e84574f88de7b17abacb2e477a6a658fa54c6083ecbda1e6ae404c7720244cd198903848fca70ca + languageName: node + linkType: hard + +"is-plain-object@npm:^5.0.0": + version: 5.0.0 + resolution: "is-plain-object@npm:5.0.0" + checksum: e32d27061eef62c0847d303125440a38660517e586f2f3db7c9d179ae5b6674ab0f469d519b2e25c147a1a3bc87156d0d5f4d8821e0ce4a9ee7fe1fcf11ce45c + languageName: node + linkType: hard + +"is-potential-custom-element-name@npm:^1.0.1": + version: 1.0.1 + resolution: "is-potential-custom-element-name@npm:1.0.1" + checksum: ced7bbbb6433a5b684af581872afe0e1767e2d1146b2207ca0068a648fb5cab9d898495d1ac0583524faaf24ca98176a7d9876363097c2d14fee6dd324f3a1ab + languageName: node + linkType: hard + +"is-promise@npm:^2.1.0, is-promise@npm:^2.2.2": + version: 2.2.2 + resolution: "is-promise@npm:2.2.2" + checksum: 18bf7d1c59953e0ad82a1ed963fb3dc0d135c8f299a14f89a17af312fc918373136e56028e8831700e1933519630cc2fd4179a777030330fde20d34e96f40c78 + languageName: node + linkType: hard + +"is-regex@npm:^1.1.4": + version: 1.1.4 + resolution: "is-regex@npm:1.1.4" + dependencies: + call-bind: ^1.0.2 + has-tostringtag: ^1.0.0 + checksum: 362399b33535bc8f386d96c45c9feb04cf7f8b41c182f54174c1a45c9abbbe5e31290bbad09a458583ff6bf3b2048672cdb1881b13289569a7c548370856a652 + languageName: node + linkType: hard + +"is-shared-array-buffer@npm:^1.0.2": + version: 1.0.2 + resolution: "is-shared-array-buffer@npm:1.0.2" + dependencies: + call-bind: ^1.0.2 + checksum: 9508929cf14fdc1afc9d61d723c6e8d34f5e117f0bffda4d97e7a5d88c3a8681f633a74f8e3ad1fe92d5113f9b921dc5ca44356492079612f9a247efbce7032a + languageName: node + linkType: hard + +"is-ssh@npm:^1.4.0": + version: 1.4.0 + resolution: "is-ssh@npm:1.4.0" + dependencies: + protocols: ^2.0.1 + checksum: 75eaa17b538bee24b661fbeb0f140226ac77e904a6039f787bea418431e2162f1f9c4c4ccad3bd169e036cd701cc631406e8c505d9fa7e20164e74b47f86f40f + languageName: node + linkType: hard + +"is-stream@npm:2.0.0, is-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "is-stream@npm:2.0.0" + checksum: 4dc47738e26bc4f1b3be9070b6b9e39631144f204fc6f87db56961220add87c10a999ba26cf81699f9ef9610426f69cb08a4713feff8deb7d8cadac907826935 + languageName: node + linkType: hard + +"is-stream@npm:^3.0.0": + version: 3.0.0 + resolution: "is-stream@npm:3.0.0" + checksum: 172093fe99119ffd07611ab6d1bcccfe8bc4aa80d864b15f43e63e54b7abc71e779acd69afdb854c4e2a67fdc16ae710e370eda40088d1cfc956a50ed82d8f16 + languageName: node + linkType: hard + +"is-string@npm:^1.0.5, is-string@npm:^1.0.7": + version: 1.0.7 + resolution: "is-string@npm:1.0.7" + dependencies: + has-tostringtag: ^1.0.0 + checksum: 323b3d04622f78d45077cf89aab783b2f49d24dc641aa89b5ad1a72114cfeff2585efc8c12ef42466dff32bde93d839ad321b26884cf75e5a7892a938b089989 + languageName: node + linkType: hard + +"is-symbol@npm:^1.0.2, is-symbol@npm:^1.0.3": + version: 1.0.4 + resolution: "is-symbol@npm:1.0.4" + dependencies: + has-symbols: ^1.0.2 + checksum: 92805812ef590738d9de49d677cd17dfd486794773fb6fa0032d16452af46e9b91bb43ffe82c983570f015b37136f4b53b28b8523bfb10b0ece7a66c31a54510 + languageName: node + linkType: hard + +"is-text-path@npm:^1.0.1": + version: 1.0.1 + resolution: "is-text-path@npm:1.0.1" + dependencies: + text-extensions: ^1.0.0 + checksum: fb5d78752c22b3f73a7c9540768f765ffcfa38c9e421e2b9af869565307fa1ae5e3d3a2ba016a43549742856846566d327da406e94a5846ec838a288b1704fd2 + languageName: node + linkType: hard + +"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.9": + version: 1.1.10 + resolution: "is-typed-array@npm:1.1.10" + dependencies: + available-typed-arrays: ^1.0.5 + call-bind: ^1.0.2 + for-each: ^0.3.3 + gopd: ^1.0.1 + has-tostringtag: ^1.0.0 + checksum: aac6ecb59d4c56a1cdeb69b1f129154ef462bbffe434cb8a8235ca89b42f258b7ae94073c41b3cb7bce37f6a1733ad4499f07882d5d5093a7ba84dfc4ebb8017 + languageName: node + linkType: hard + +"is-typedarray@npm:~1.0.0": + version: 1.0.0 + resolution: "is-typedarray@npm:1.0.0" + checksum: 3508c6cd0a9ee2e0df2fa2e9baabcdc89e911c7bd5cf64604586697212feec525aa21050e48affb5ffc3df20f0f5d2e2cf79b08caa64e1ccc9578e251763aef7 + languageName: node + linkType: hard + +"is-unicode-supported@npm:^0.1.0": + version: 0.1.0 + resolution: "is-unicode-supported@npm:0.1.0" + checksum: a2aab86ee7712f5c2f999180daaba5f361bdad1efadc9610ff5b8ab5495b86e4f627839d085c6530363c6d6d4ecbde340fb8e54bdb83da4ba8e0865ed5513c52 + languageName: node + linkType: hard + +"is-unicode-supported@npm:^1.1.0, is-unicode-supported@npm:^1.2.0": + version: 1.3.0 + resolution: "is-unicode-supported@npm:1.3.0" + checksum: 20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc + languageName: node + linkType: hard + +"is-weakref@npm:^1.0.2": + version: 1.0.2 + resolution: "is-weakref@npm:1.0.2" + dependencies: + call-bind: ^1.0.2 + checksum: 95bd9a57cdcb58c63b1c401c60a474b0f45b94719c30f548c891860f051bc2231575c290a6b420c6bc6e7ed99459d424c652bd5bf9a1d5259505dc35b4bf83de + languageName: node + linkType: hard + +"is-wsl@npm:^2.2.0": + version: 2.2.0 + resolution: "is-wsl@npm:2.2.0" + dependencies: + is-docker: ^2.0.0 + checksum: 20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 + languageName: node + linkType: hard + +"is@npm:^3.2.1": + version: 3.3.0 + resolution: "is@npm:3.3.0" + checksum: 81fad3b40c606984c2d0699207c4c48d2a0d29cc834b274d0b74c172f3eeebdb981301fe0d690ce090a96bf021a8a1f8b1325262ad9870c525e557ac4a559c56 + languageName: node + linkType: hard + +"isarray@npm:~1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 + languageName: node + linkType: hard + +"isobject@npm:^3.0.1": + version: 3.0.1 + resolution: "isobject@npm:3.0.1" + checksum: db85c4c970ce30693676487cca0e61da2ca34e8d4967c2e1309143ff910c207133a969f9e4ddb2dc6aba670aabce4e0e307146c310350b298e74a31f7d464703 + languageName: node + linkType: hard + +"isomorphic.js@npm:^0.2.4": + version: 0.2.5 + resolution: "isomorphic.js@npm:0.2.5" + checksum: d8d1b083f05f3c337a06628b982ac3ce6db953bbef14a9de8ad49131250c3592f864b73c12030fdc9ef138ce97b76ef55c7d96a849561ac215b1b4b9d301c8e9 + languageName: node + linkType: hard + +"isstream@npm:~0.1.2": + version: 0.1.2 + resolution: "isstream@npm:0.1.2" + checksum: 1eb2fe63a729f7bdd8a559ab552c69055f4f48eb5c2f03724430587c6f450783c8f1cd936c1c952d0a927925180fcc892ebd5b174236cf1065d4bd5bdb37e963 + languageName: node + linkType: hard + +"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": + version: 3.2.0 + resolution: "istanbul-lib-coverage@npm:3.2.0" + checksum: a2a545033b9d56da04a8571ed05c8120bf10e9bce01cf8633a3a2b0d1d83dff4ac4fe78d6d5673c27fc29b7f21a41d75f83a36be09f82a61c367b56aa73c1ff9 + languageName: node + linkType: hard + +"istanbul-lib-instrument@npm:^5.0.4, istanbul-lib-instrument@npm:^5.1.0": + version: 5.2.1 + resolution: "istanbul-lib-instrument@npm:5.2.1" + dependencies: + "@babel/core": ^7.12.3 + "@babel/parser": ^7.14.7 + "@istanbuljs/schema": ^0.1.2 + istanbul-lib-coverage: ^3.2.0 + semver: ^6.3.0 + checksum: bf16f1803ba5e51b28bbd49ed955a736488381e09375d830e42ddeb403855b2006f850711d95ad726f2ba3f1ae8e7366de7e51d2b9ac67dc4d80191ef7ddf272 + languageName: node + linkType: hard + +"istanbul-lib-report@npm:^3.0.0": + version: 3.0.0 + resolution: "istanbul-lib-report@npm:3.0.0" + dependencies: + istanbul-lib-coverage: ^3.0.0 + make-dir: ^3.0.0 + supports-color: ^7.1.0 + checksum: 3f29eb3f53c59b987386e07fe772d24c7f58c6897f34c9d7a296f4000de7ae3de9eb95c3de3df91dc65b134c84dee35c54eee572a56243e8907c48064e34ff1b + languageName: node + linkType: hard + +"istanbul-lib-source-maps@npm:^4.0.0": + version: 4.0.1 + resolution: "istanbul-lib-source-maps@npm:4.0.1" + dependencies: + debug: ^4.1.1 + istanbul-lib-coverage: ^3.0.0 + source-map: ^0.6.1 + checksum: 21ad3df45db4b81852b662b8d4161f6446cd250c1ddc70ef96a585e2e85c26ed7cd9c2a396a71533cfb981d1a645508bc9618cae431e55d01a0628e7dec62ef2 + languageName: node + linkType: hard + +"istanbul-reports@npm:^3.1.3": + version: 3.1.5 + resolution: "istanbul-reports@npm:3.1.5" + dependencies: + html-escaper: ^2.0.0 + istanbul-lib-report: ^3.0.0 + checksum: 7867228f83ed39477b188ea07e7ccb9b4f5320b6f73d1db93a0981b7414fa4ef72d3f80c4692c442f90fc250d9406e71d8d7ab65bb615cb334e6292b73192b89 + languageName: node + linkType: hard + +"jackspeak@npm:^2.0.3": + version: 2.2.1 + resolution: "jackspeak@npm:2.2.1" + dependencies: + "@isaacs/cliui": ^8.0.2 + "@pkgjs/parseargs": ^0.11.0 + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: e29291c0d0f280a063fa18fbd1e891ab8c2d7519fd34052c0ebde38538a15c603140d60c2c7f432375ff7ee4c5f1c10daa8b2ae19a97c3d4affe308c8360c1df + languageName: node + linkType: hard + +"jake@npm:^10.8.5": + version: 10.8.5 + resolution: "jake@npm:10.8.5" + dependencies: + async: ^3.2.3 + chalk: ^4.0.2 + filelist: ^1.0.1 + minimatch: ^3.0.4 + bin: + jake: ./bin/cli.js + checksum: 56c913ecf5a8d74325d0af9bc17a233bad50977438d44864d925bb6c45c946e0fee8c4c1f5fe2225471ef40df5222e943047982717ebff0d624770564d3c46ba + languageName: node + linkType: hard + +"jest-changed-files@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-changed-files@npm:29.5.0" + dependencies: + execa: ^5.0.0 + p-limit: ^3.1.0 + checksum: a67a7cb3c11f8f92bd1b7c79e84f724cbd11a9ad51f3cdadafe3ce7ee3c79ee50dbea128f920f5fddc807e9e4e83f5462143094391feedd959a77dd20ab96cf3 + languageName: node + linkType: hard + +"jest-circus@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-circus@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/expect": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + co: ^4.6.0 + dedent: ^0.7.0 + is-generator-fn: ^2.0.0 + jest-each: ^29.5.0 + jest-matcher-utils: ^29.5.0 + jest-message-util: ^29.5.0 + jest-runtime: ^29.5.0 + jest-snapshot: ^29.5.0 + jest-util: ^29.5.0 + p-limit: ^3.1.0 + pretty-format: ^29.5.0 + pure-rand: ^6.0.0 + slash: ^3.0.0 + stack-utils: ^2.0.3 + checksum: 44ff5d06acedae6de6c866e20e3b61f83e29ab94cf9f960826e7e667de49c12dd9ab9dffd7fa3b7d1f9688a8b5bfb1ebebadbea69d9ed0d3f66af4a0ff8c2b27 + languageName: node + linkType: hard + +"jest-cli@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-cli@npm:29.5.0" + dependencies: + "@jest/core": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/types": ^29.5.0 + chalk: ^4.0.0 + exit: ^0.1.2 + graceful-fs: ^4.2.9 + import-local: ^3.0.2 + jest-config: ^29.5.0 + jest-util: ^29.5.0 + jest-validate: ^29.5.0 + prompts: ^2.0.1 + yargs: ^17.3.1 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: 39897bbbc0f0d8a6b975ab12fd13887eaa28d92e3dee9e0173a5cb913ae8cc2ae46e090d38c6d723e84d9d6724429cd08685b4e505fa447d31ca615630c7dbba + languageName: node + linkType: hard + +"jest-config@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-config@npm:29.5.0" + dependencies: + "@babel/core": ^7.11.6 + "@jest/test-sequencer": ^29.5.0 + "@jest/types": ^29.5.0 + babel-jest: ^29.5.0 + chalk: ^4.0.0 + ci-info: ^3.2.0 + deepmerge: ^4.2.2 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + jest-circus: ^29.5.0 + jest-environment-node: ^29.5.0 + jest-get-type: ^29.4.3 + jest-regex-util: ^29.4.3 + jest-resolve: ^29.5.0 + jest-runner: ^29.5.0 + jest-util: ^29.5.0 + jest-validate: ^29.5.0 + micromatch: ^4.0.4 + parse-json: ^5.2.0 + pretty-format: ^29.5.0 + slash: ^3.0.0 + strip-json-comments: ^3.1.1 + peerDependencies: + "@types/node": "*" + ts-node: ">=9.0.0" + peerDependenciesMeta: + "@types/node": + optional: true + ts-node: + optional: true + checksum: c37c4dab964c54ab293d4e302d40b09687037ac9d00b88348ec42366970747feeaf265e12e3750cd3660b40c518d4031335eda11ac10b70b10e60797ebbd4b9c + languageName: node + linkType: hard + +"jest-diff@npm:>=29.4.3 < 30, jest-diff@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-diff@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + diff-sequences: ^29.4.3 + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: dfd0f4a299b5d127779c76b40106c37854c89c3e0785098c717d52822d6620d227f6234c3a9291df204d619e799e3654159213bf93220f79c8e92a55475a3d39 + languageName: node + linkType: hard + +"jest-docblock@npm:^29.4.3": + version: 29.4.3 + resolution: "jest-docblock@npm:29.4.3" + dependencies: + detect-newline: ^3.0.0 + checksum: e0e9df1485bb8926e5b33478cdf84b3387d9caf3658e7dc1eaa6dc34cb93dea0d2d74797f6e940f0233a88f3dadd60957f2288eb8f95506361f85b84bf8661df + languageName: node + linkType: hard + +"jest-each@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-each@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + chalk: ^4.0.0 + jest-get-type: ^29.4.3 + jest-util: ^29.5.0 + pretty-format: ^29.5.0 + checksum: b8b297534d25834c5d4e31e4c687359787b1e402519e42664eb704cc3a12a7a91a017565a75acb02e8cf9afd3f4eef3350bd785276bec0900184641b765ff7a5 + languageName: node + linkType: hard + +"jest-environment-jsdom@npm:^29.3.0": + version: 29.5.0 + resolution: "jest-environment-jsdom@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/fake-timers": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/jsdom": ^20.0.0 + "@types/node": "*" + jest-mock: ^29.5.0 + jest-util: ^29.5.0 + jsdom: ^20.0.0 + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + checksum: 3df7fc85275711f20b483ac8cd8c04500704ed0f69791eb55c574b38f5a39470f03d775cf20c1025bc1884916ac0573aa2fa4db1bb74225bc7fdd95ba97ad0da + languageName: node + linkType: hard + +"jest-environment-node@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-environment-node@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/fake-timers": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + jest-mock: ^29.5.0 + jest-util: ^29.5.0 + checksum: 57981911cc20a4219b0da9e22b2e3c9f31b505e43f78e61c899e3227ded455ce1a3a9483842c69cfa4532f02cfb536ae0995bf245f9211608edacfc1e478d411 + languageName: node + linkType: hard + +"jest-get-type@npm:^29.4.3": + version: 29.4.3 + resolution: "jest-get-type@npm:29.4.3" + checksum: 6ac7f2dde1c65e292e4355b6c63b3a4897d7e92cb4c8afcf6d397f2682f8080e094c8b0b68205a74d269882ec06bf696a9de6cd3e1b7333531e5ed7b112605ce + languageName: node + linkType: hard + +"jest-haste-map@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-haste-map@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/graceful-fs": ^4.1.3 + "@types/node": "*" + anymatch: ^3.0.3 + fb-watchman: ^2.0.0 + fsevents: ^2.3.2 + graceful-fs: ^4.2.9 + jest-regex-util: ^29.4.3 + jest-util: ^29.5.0 + jest-worker: ^29.5.0 + micromatch: ^4.0.4 + walker: ^1.0.8 + dependenciesMeta: + fsevents: + optional: true + checksum: 3828ff7783f168e34be2c63887f82a01634261f605dcae062d83f979a61c37739e21b9607ecb962256aea3fbe5a530a1acee062d0026fcb47c607c12796cf3b7 + languageName: node + linkType: hard + +"jest-junit@npm:^15.0.0": + version: 15.0.0 + resolution: "jest-junit@npm:15.0.0" + dependencies: + mkdirp: ^1.0.4 + strip-ansi: ^6.0.1 + uuid: ^8.3.2 + xml: ^1.0.1 + checksum: e8fe4d2f2ab843383ac41820a6fe495739d154ec435cd44ba590b44ec7fd62095676f3eef13f98392f81d4a3727ea58b4f4fad231fe367ac31243952b9ad716f + languageName: node + linkType: hard + +"jest-leak-detector@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-leak-detector@npm:29.5.0" + dependencies: + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: 0fb845da7ac9cdfc9b3b2e35f6f623a41c547d7dc0103ceb0349013459d00de5870b5689a625e7e37f9644934b40e8f1dcdd5422d14d57470600350364676313 + languageName: node + linkType: hard + +"jest-matcher-utils@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-matcher-utils@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + jest-diff: ^29.5.0 + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: 1d3e8c746e484a58ce194e3aad152eff21fd0896e8b8bf3d4ab1a4e2cbfed95fb143646f4ad9fdf6e42212b9e8fc033268b58e011b044a9929df45485deb5ac9 + languageName: node + linkType: hard + +"jest-message-util@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-message-util@npm:29.5.0" + dependencies: + "@babel/code-frame": ^7.12.13 + "@jest/types": ^29.5.0 + "@types/stack-utils": ^2.0.0 + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + micromatch: ^4.0.4 + pretty-format: ^29.5.0 + slash: ^3.0.0 + stack-utils: ^2.0.3 + checksum: daddece6bbf846eb6a2ab9be9f2446e54085bef4e5cecd13d2a538fa9c01cb89d38e564c6b74fd8e12d37ed9eface8a362240ae9f21d68b214590631e7a0d8bf + languageName: node + linkType: hard + +"jest-mock@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-mock@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/node": "*" + jest-util: ^29.5.0 + checksum: 2a9cf07509948fa8608898c445f04fe4dd6e2049ff431e5531eee028c808d3ba3c67f226ac87b0cf383feaa1055776900d197c895e89783016886ac17a4ff10c + languageName: node + linkType: hard + +"jest-pnp-resolver@npm:^1.2.2": + version: 1.2.3 + resolution: "jest-pnp-resolver@npm:1.2.3" + peerDependencies: + jest-resolve: "*" + peerDependenciesMeta: + jest-resolve: + optional: true + checksum: db1a8ab2cb97ca19c01b1cfa9a9c8c69a143fde833c14df1fab0766f411b1148ff0df878adea09007ac6a2085ec116ba9a996a6ad104b1e58c20adbf88eed9b2 + languageName: node + linkType: hard + +"jest-regex-util@npm:^29.4.3": + version: 29.4.3 + resolution: "jest-regex-util@npm:29.4.3" + checksum: 96fc7fc28cd4dd73a63c13a526202c4bd8b351d4e5b68b1a2a2c88da3308c2a16e26feaa593083eb0bac38cca1aa9dd05025412e7de013ba963fb8e66af22b8a + languageName: node + linkType: hard + +"jest-resolve-dependencies@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-resolve-dependencies@npm:29.5.0" + dependencies: + jest-regex-util: ^29.4.3 + jest-snapshot: ^29.5.0 + checksum: 479d2e5365d58fe23f2b87001e2e0adcbffe0147700e85abdec8f14b9703b0a55758c1929a9989e3f5d5e954fb88870ea4bfa04783523b664562fcf5f10b0edf + languageName: node + linkType: hard + +"jest-resolve@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-resolve@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.5.0 + jest-pnp-resolver: ^1.2.2 + jest-util: ^29.5.0 + jest-validate: ^29.5.0 + resolve: ^1.20.0 + resolve.exports: ^2.0.0 + slash: ^3.0.0 + checksum: 9a125f3cf323ceef512089339d35f3ee37f79fe16a831fb6a26773ea6a229b9e490d108fec7af334142e91845b5996de8e7cdd85a4d8d617078737d804e29c8f + languageName: node + linkType: hard + +"jest-runner@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-runner@npm:29.5.0" + dependencies: + "@jest/console": ^29.5.0 + "@jest/environment": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + emittery: ^0.13.1 + graceful-fs: ^4.2.9 + jest-docblock: ^29.4.3 + jest-environment-node: ^29.5.0 + jest-haste-map: ^29.5.0 + jest-leak-detector: ^29.5.0 + jest-message-util: ^29.5.0 + jest-resolve: ^29.5.0 + jest-runtime: ^29.5.0 + jest-util: ^29.5.0 + jest-watcher: ^29.5.0 + jest-worker: ^29.5.0 + p-limit: ^3.1.0 + source-map-support: 0.5.13 + checksum: 437dea69c5dddca22032259787bac74790d5a171c9d804711415f31e5d1abfb64fa52f54a9015bb17a12b858fd0cf3f75ef6f3c9e94255a8596e179f707229c4 + languageName: node + linkType: hard + +"jest-runtime@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-runtime@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/fake-timers": ^29.5.0 + "@jest/globals": ^29.5.0 + "@jest/source-map": ^29.4.3 + "@jest/test-result": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + cjs-module-lexer: ^1.0.0 + collect-v8-coverage: ^1.0.0 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.5.0 + jest-message-util: ^29.5.0 + jest-mock: ^29.5.0 + jest-regex-util: ^29.4.3 + jest-resolve: ^29.5.0 + jest-snapshot: ^29.5.0 + jest-util: ^29.5.0 + slash: ^3.0.0 + strip-bom: ^4.0.0 + checksum: 7af27bd9d54cf1c5735404cf8d76c6509d5610b1ec0106a21baa815c1aff15d774ce534ac2834bc440dccfe6348bae1885fd9a806f23a94ddafdc0f5bae4b09d + languageName: node + linkType: hard + +"jest-snapshot@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-snapshot@npm:29.5.0" + dependencies: + "@babel/core": ^7.11.6 + "@babel/generator": ^7.7.2 + "@babel/plugin-syntax-jsx": ^7.7.2 + "@babel/plugin-syntax-typescript": ^7.7.2 + "@babel/traverse": ^7.7.2 + "@babel/types": ^7.3.3 + "@jest/expect-utils": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/babel__traverse": ^7.0.6 + "@types/prettier": ^2.1.5 + babel-preset-current-node-syntax: ^1.0.0 + chalk: ^4.0.0 + expect: ^29.5.0 + graceful-fs: ^4.2.9 + jest-diff: ^29.5.0 + jest-get-type: ^29.4.3 + jest-matcher-utils: ^29.5.0 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + natural-compare: ^1.4.0 + pretty-format: ^29.5.0 + semver: ^7.3.5 + checksum: fe5df54122ed10eed625de6416a45bc4958d5062b018f05b152bf9785ab7f355dcd55e40cf5da63895bf8278f8d7b2bb4059b2cfbfdee18f509d455d37d8aa2b + languageName: node + linkType: hard + +"jest-util@npm:^29.0.0, jest-util@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-util@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + ci-info: ^3.2.0 + graceful-fs: ^4.2.9 + picomatch: ^2.2.3 + checksum: fd9212950d34d2ecad8c990dda0d8ea59a8a554b0c188b53ea5d6c4a0829a64f2e1d49e6e85e812014933d17426d7136da4785f9cf76fff1799de51b88bc85d3 + languageName: node + linkType: hard + +"jest-validate@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-validate@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + camelcase: ^6.2.0 + chalk: ^4.0.0 + jest-get-type: ^29.4.3 + leven: ^3.1.0 + pretty-format: ^29.5.0 + checksum: 43ca5df7cb75572a254ac3e92fbbe7be6b6a1be898cc1e887a45d55ea003f7a112717d814a674d37f9f18f52d8de40873c8f084f17664ae562736c78dd44c6a1 + languageName: node + linkType: hard + +"jest-watcher@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-watcher@npm:29.5.0" + dependencies: + "@jest/test-result": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + ansi-escapes: ^4.2.1 + chalk: ^4.0.0 + emittery: ^0.13.1 + jest-util: ^29.5.0 + string-length: ^4.0.1 + checksum: 62303ac7bdc7e61a8b4239a239d018f7527739da2b2be6a81a7be25b74ca769f1c43ee8558ce8e72bb857245c46d6e03af331227ffb00a57280abb2a928aa776 + languageName: node + linkType: hard + +"jest-worker@npm:^27.4.5": + version: 27.5.1 + resolution: "jest-worker@npm:27.5.1" + dependencies: + "@types/node": "*" + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: 98cd68b696781caed61c983a3ee30bf880b5bd021c01d98f47b143d4362b85d0737f8523761e2713d45e18b4f9a2b98af1eaee77afade4111bb65c77d6f7c980 + languageName: node + linkType: hard + +"jest-worker@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-worker@npm:29.5.0" + dependencies: + "@types/node": "*" + jest-util: ^29.5.0 + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: 1151a1ae3602b1ea7c42a8f1efe2b5a7bf927039deaa0827bf978880169899b705744e288f80a63603fb3fc2985e0071234986af7dc2c21c7a64333d8777c7c9 + languageName: node + linkType: hard + +"jest@npm:^29.2.0": + version: 29.5.0 + resolution: "jest@npm:29.5.0" + dependencies: + "@jest/core": ^29.5.0 + "@jest/types": ^29.5.0 + import-local: ^3.0.2 + jest-cli: ^29.5.0 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: a8ff2eb0f421623412236e23cbe67c638127fffde466cba9606bc0c0553b4c1e5cb116d7e0ef990b5d1712851652c8ee461373b578df50857fe635b94ff455d5 + languageName: node + linkType: hard + +"js-sdsl@npm:^4.1.4": + version: 4.3.0 + resolution: "js-sdsl@npm:4.3.0" + checksum: ce908257cf6909e213af580af3a691a736f5ee8b16315454768f917a682a4ea0c11bde1b241bbfaecedc0eb67b72101b2c2df2ffaed32aed5d539fca816f054e + languageName: node + linkType: hard + +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 + languageName: node + linkType: hard + +"js-yaml@npm:4.1.0, js-yaml@npm:^4.1.0": + version: 4.1.0 + resolution: "js-yaml@npm:4.1.0" + dependencies: + argparse: ^2.0.1 + bin: + js-yaml: bin/js-yaml.js + checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a + languageName: node + linkType: hard + +"js-yaml@npm:^3.10.0, js-yaml@npm:^3.12.1, js-yaml@npm:^3.13.1": + version: 3.14.1 + resolution: "js-yaml@npm:3.14.1" + dependencies: + argparse: ^1.0.7 + esprima: ^4.0.0 + bin: + js-yaml: bin/js-yaml.js + checksum: bef146085f472d44dee30ec34e5cf36bf89164f5d585435a3d3da89e52622dff0b188a580e4ad091c3341889e14cb88cac6e4deb16dc5b1e9623bb0601fc255c + languageName: node + linkType: hard + +"jsbn@npm:~0.1.0": + version: 0.1.1 + resolution: "jsbn@npm:0.1.1" + checksum: e5ff29c1b8d965017ef3f9c219dacd6e40ad355c664e277d31246c90545a02e6047018c16c60a00f36d561b3647215c41894f5d869ada6908a2e0ce4200c88f2 + languageName: node + linkType: hard + +"jsdom@npm:^20.0.0": + version: 20.0.3 + resolution: "jsdom@npm:20.0.3" + dependencies: + abab: ^2.0.6 + acorn: ^8.8.1 + acorn-globals: ^7.0.0 + cssom: ^0.5.0 + cssstyle: ^2.3.0 + data-urls: ^3.0.2 + decimal.js: ^10.4.2 + domexception: ^4.0.0 + escodegen: ^2.0.0 + form-data: ^4.0.0 + html-encoding-sniffer: ^3.0.0 + http-proxy-agent: ^5.0.0 + https-proxy-agent: ^5.0.1 + is-potential-custom-element-name: ^1.0.1 + nwsapi: ^2.2.2 + parse5: ^7.1.1 + saxes: ^6.0.0 + symbol-tree: ^3.2.4 + tough-cookie: ^4.1.2 + w3c-xmlserializer: ^4.0.0 + webidl-conversions: ^7.0.0 + whatwg-encoding: ^2.0.0 + whatwg-mimetype: ^3.0.0 + whatwg-url: ^11.0.0 + ws: ^8.11.0 + xml-name-validator: ^4.0.0 + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + checksum: 6e2ae21db397133a061b270c26d2dbc0b9051733ea3b896a7ece78d79f475ff0974f766a413c1198a79c793159119169f2335ddb23150348fbfdcfa6f3105536 + languageName: node + linkType: hard + +"jsesc@npm:^2.5.1": + version: 2.5.2 + resolution: "jsesc@npm:2.5.2" + bin: + jsesc: bin/jsesc + checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d + languageName: node + linkType: hard + +"jsesc@npm:~0.5.0": + version: 0.5.0 + resolution: "jsesc@npm:0.5.0" + bin: + jsesc: bin/jsesc + checksum: b8b44cbfc92f198ad972fba706ee6a1dfa7485321ee8c0b25f5cedd538dcb20cde3197de16a7265430fce8277a12db066219369e3d51055038946039f6e20e17 + languageName: node + linkType: hard + +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 9026b03edc2847eefa2e37646c579300a1f3a4586cfb62bf857832b60c852042d0d6ae55d1afb8926163fa54c2b01d83ae24705f34990348bdac6273a29d4581 + languageName: node + linkType: hard + +"json-file-plus@npm:^3.3.1": + version: 3.3.1 + resolution: "json-file-plus@npm:3.3.1" + dependencies: + is: ^3.2.1 + node.extend: ^2.0.0 + object.assign: ^4.1.0 + promiseback: ^2.0.2 + safer-buffer: ^2.0.2 + checksum: 162c7a0c8f3e5a7eeea945aac4f2578c11567c87d3e2eafdd9db6972d1fc8657cc1e04b8a23ff3731759da794057a932f251a4db06a267abf5d181977753cf38 + languageName: node + linkType: hard + +"json-parse-better-errors@npm:^1.0.1": + version: 1.0.2 + resolution: "json-parse-better-errors@npm:1.0.2" + checksum: ff2b5ba2a70e88fd97a3cb28c1840144c5ce8fae9cbeeddba15afa333a5c407cf0e42300cd0a2885dbb055227fe68d405070faad941beeffbfde9cf3b2c78c5d + languageName: node + linkType: hard + +"json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 798ed4cf3354a2d9ccd78e86d2169515a0097a5c133337807cdf7f1fc32e1391d207ccfc276518cc1d7d8d4db93288b8a50ba4293d212ad1336e52a8ec0a941f + languageName: node + linkType: hard + +"json-parse-even-better-errors@npm:^3.0.0": + version: 3.0.0 + resolution: "json-parse-even-better-errors@npm:3.0.0" + checksum: f1970b5220c7fa23d888565510752c3d5e863f93668a202fcaa719739fa41485dfc6a1db212f702ebd3c873851cc067aebc2917e3f79763cae2fdb95046f38f3 + languageName: node + linkType: hard + +"json-schema-compare@npm:^0.2.2": + version: 0.2.2 + resolution: "json-schema-compare@npm:0.2.2" + dependencies: + lodash: ^4.17.4 + checksum: dd6f2173857c8e3b77d6ebdfa05bd505bba5b08709ab46b532722f5d1c33b5fee1fc8f3c97d0c0d011db25f9f3b0baf7ab783bb5f55c32abd9f1201760e43c2c + languageName: node + linkType: hard + +"json-schema-merge-allof@npm:^0.8.1": + version: 0.8.1 + resolution: "json-schema-merge-allof@npm:0.8.1" + dependencies: + compute-lcm: ^1.1.2 + json-schema-compare: ^0.2.2 + lodash: ^4.17.20 + checksum: 82700f6ac77351959138d6b153d77375a8c29cf48d907241b85c8292dd77aabd8cb816400f2b0d17062c4ccc8893832ec4f664ab9c814927ef502e7a595ea873 + languageName: node + linkType: hard + +"json-schema-ref-parser@npm:^6.1.0": + version: 6.1.0 + resolution: "json-schema-ref-parser@npm:6.1.0" + dependencies: + call-me-maybe: ^1.0.1 + js-yaml: ^3.12.1 + ono: ^4.0.11 + checksum: 03944fcb5b3d73181b5c90ec06a8b0fd1f744f366b6f956e1df9d42117172427b7476ff82c3def0e932272dfdfec77c14e024ca67a5dfc36175eb272e87421dd + languageName: node + linkType: hard + +"json-schema-to-typescript@npm:^8.0.0": + version: 8.2.0 + resolution: "json-schema-to-typescript@npm:8.2.0" + dependencies: + "@types/is-glob": ^4.0.1 + "@types/json-schema": ^7.0.3 + "@types/mkdirp": ^0.5.2 + "@types/prettier": ^1.16.1 + cli-color: ^1.4.0 + glob: ^7.1.4 + is-glob: ^4.0.1 + json-schema-ref-parser: ^6.1.0 + json-stringify-safe: ^5.0.1 + lodash: ^4.17.11 + minimist: ^1.2.0 + mkdirp: ^0.5.1 + mz: ^2.7.0 + prettier: ^1.19.1 + stdin: 0.0.1 + bin: + json2ts: dist/src/cli.js + checksum: 4327a6983be0eccc1dc1823c185c10b6287425d1a283b96ea88f5d6d61c71a031343bd6c5d5e7d30c0ba1c0b413655978a766a744d04707ce68417e0e2ccd2c0 + languageName: node + linkType: hard + +"json-schema-traverse@npm:^0.4.1": + version: 0.4.1 + resolution: "json-schema-traverse@npm:0.4.1" + checksum: 7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b + languageName: node + linkType: hard + +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad + languageName: node + linkType: hard + +"json-schema@npm:0.4.0, json-schema@npm:^0.4.0": + version: 0.4.0 + resolution: "json-schema@npm:0.4.0" + checksum: 66389434c3469e698da0df2e7ac5a3281bcff75e797a5c127db7c5b56270e01ae13d9afa3c03344f76e32e81678337a8c912bdbb75101c62e487dc3778461d72 + languageName: node + linkType: hard + +"json-stable-stringify-without-jsonify@npm:^1.0.1": + version: 1.0.1 + resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" + checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215 + languageName: node + linkType: hard + +"json-stringify-pretty-compact@npm:^3.0.0, json-stringify-pretty-compact@npm:~3.0.0": + version: 3.0.0 + resolution: "json-stringify-pretty-compact@npm:3.0.0" + checksum: 01ab5c5c8260299414868d96db97f53aef93c290fe469edd9a1363818e795006e01c952fa2fd7b47cbbab506d5768998eccc25e1da4fa2ccfebd1788c6098791 + languageName: node + linkType: hard + +"json-stringify-safe@npm:^5.0.1, json-stringify-safe@npm:~5.0.1": + version: 5.0.1 + resolution: "json-stringify-safe@npm:5.0.1" + checksum: 48ec0adad5280b8a96bb93f4563aa1667fd7a36334f79149abd42446d0989f2ddc58274b479f4819f1f00617957e6344c886c55d05a4e15ebb4ab931e4a6a8ee + languageName: node + linkType: hard + +"json-to-html@npm:~0.1.2": + version: 0.1.2 + resolution: "json-to-html@npm:0.1.2" + checksum: 434bd7fb3364af05b0d48d13bfcc8a4fc00624100a7418cb2ca5e3eb99c52b744dbd5da9d33c8a8ad0b682cb04ad7a86fd27f69fce6151f5399b9d7e350c748c + languageName: node + linkType: hard + +"json5@npm:^2.1.2, json5@npm:^2.2.2, json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 + languageName: node + linkType: hard + +"jsonc-parser@npm:3.2.0, jsonc-parser@npm:^3.2.0": + version: 3.2.0 + resolution: "jsonc-parser@npm:3.2.0" + checksum: 946dd9a5f326b745aa326d48a7257e3f4a4b62c5e98ec8e49fa2bdd8d96cef7e6febf1399f5c7016114fd1f68a1c62c6138826d5d90bc650448e3cf0951c53c7 + languageName: node + linkType: hard + +"jsonfile@npm:^6.0.1": + version: 6.1.0 + resolution: "jsonfile@npm:6.1.0" + dependencies: + graceful-fs: ^4.1.6 + universalify: ^2.0.0 + dependenciesMeta: + graceful-fs: + optional: true + checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 + languageName: node + linkType: hard + +"jsonparse@npm:^1.2.0, jsonparse@npm:^1.3.1": + version: 1.3.1 + resolution: "jsonparse@npm:1.3.1" + checksum: 6514a7be4674ebf407afca0eda3ba284b69b07f9958a8d3113ef1005f7ec610860c312be067e450c569aab8b89635e332cee3696789c750692bb60daba627f4d + languageName: node + linkType: hard + +"jsonpointer@npm:^5.0.1": + version: 5.0.1 + resolution: "jsonpointer@npm:5.0.1" + checksum: 0b40f712900ad0c846681ea2db23b6684b9d5eedf55807b4708c656f5894b63507d0e28ae10aa1bddbea551241035afe62b6df0800fc94c2e2806a7f3adecd7c + languageName: node + linkType: hard + +"jsonwebtoken@npm:9.0.0": + version: 9.0.0 + resolution: "jsonwebtoken@npm:9.0.0" + dependencies: + jws: ^3.2.2 + lodash: ^4.17.21 + ms: ^2.1.1 + semver: ^7.3.8 + checksum: b9181cecf9df99f1dc0253f91ba000a1aa4d91f5816d1608c0dba61a5623726a0bfe200b51df25de18c1a6000825d231ad7ce2788aa54fd48dcb760ad9eb9514 + languageName: node + linkType: hard + +"jsprim@npm:^1.2.2": + version: 1.4.2 + resolution: "jsprim@npm:1.4.2" + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + checksum: 2ad1b9fdcccae8b3d580fa6ced25de930eaa1ad154db21bbf8478a4d30bbbec7925b5f5ff29b933fba9412b16a17bd484a8da4fdb3663b5e27af95dd693bab2a + languageName: node + linkType: hard + +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0": + version: 3.3.3 + resolution: "jsx-ast-utils@npm:3.3.3" + dependencies: + array-includes: ^3.1.5 + object.assign: ^4.1.3 + checksum: a2ed78cac49a0f0c4be8b1eafe3c5257a1411341d8e7f1ac740debae003de04e5f6372bfcfbd9d082e954ffd99aac85bcda85b7c6bc11609992483f4cdc0f745 + languageName: node + linkType: hard + +"jwa@npm:^1.4.1": + version: 1.4.1 + resolution: "jwa@npm:1.4.1" + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: ^5.0.1 + checksum: ff30ea7c2dcc61f3ed2098d868bf89d43701605090c5b21b5544b512843ec6fd9e028381a4dda466cbcdb885c2d1150f7c62e7168394ee07941b4098e1035e2f + languageName: node + linkType: hard + +"jws@npm:^3.2.2": + version: 3.2.2 + resolution: "jws@npm:3.2.2" + dependencies: + jwa: ^1.4.1 + safe-buffer: ^5.0.1 + checksum: f0213fe5b79344c56cd443428d8f65c16bf842dc8cb8f5aed693e1e91d79c20741663ad6eff07a6d2c433d1831acc9814e8d7bada6a0471fbb91d09ceb2bf5c2 + languageName: node + linkType: hard + +"keygrip@npm:~1.1.0": + version: 1.1.0 + resolution: "keygrip@npm:1.1.0" + dependencies: + tsscmp: 1.0.6 + checksum: 078cd16a463d187121f0a27c1c9c95c52ad392b620f823431689f345a0501132cee60f6e96914b07d570105af470b96960402accd6c48a0b1f3cd8fac4fa2cae + languageName: node + linkType: hard + +"keyv@npm:^4.0.0": + version: 4.5.2 + resolution: "keyv@npm:4.5.2" + dependencies: + json-buffer: 3.0.1 + checksum: 13ad58303acd2261c0d4831b4658451603fd159e61daea2121fcb15feb623e75ee328cded0572da9ca76b7b3ceaf8e614f1806c6b3af5db73c9c35a345259651 + languageName: node + linkType: hard + +"kind-of@npm:^6.0.2, kind-of@npm:^6.0.3": + version: 6.0.3 + resolution: "kind-of@npm:6.0.3" + checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b + languageName: node + linkType: hard + +"kleur@npm:4.1.5": + version: 4.1.5 + resolution: "kleur@npm:4.1.5" + checksum: 1dc476e32741acf0b1b5b0627ffd0d722e342c1b0da14de3e8ae97821327ca08f9fb944542fb3c126d90ac5f27f9d804edbe7c585bf7d12ef495d115e0f22c12 + languageName: node + linkType: hard + +"kleur@npm:^3.0.3": + version: 3.0.3 + resolution: "kleur@npm:3.0.3" + checksum: df82cd1e172f957bae9c536286265a5cdbd5eeca487cb0a3b2a7b41ef959fc61f8e7c0e9aeea9c114ccf2c166b6a8dd45a46fd619c1c569d210ecd2765ad5169 + languageName: node + linkType: hard + +"known-css-properties@npm:^0.27.0": + version: 0.27.0 + resolution: "known-css-properties@npm:0.27.0" + checksum: 8584fcf0526f984fe5a358af20200dec3b944373dd005dc23a3ce988895e1acd03e7d69c49533dda07d6d9b6d53990ed1119bd9d3e927f17545f8764c434a5cd + languageName: node + linkType: hard + +"lerna@npm:^7.1.4": + version: 7.1.4 + resolution: "lerna@npm:7.1.4" + dependencies: + "@lerna/child-process": 7.1.4 + "@lerna/create": 7.1.4 + "@npmcli/run-script": 6.0.2 + "@nx/devkit": ">=16.5.1 < 17" + "@octokit/plugin-enterprise-rest": 6.0.1 + "@octokit/rest": 19.0.11 + byte-size: 8.1.1 + chalk: 4.1.0 + clone-deep: 4.0.1 + cmd-shim: 6.0.1 + columnify: 1.6.0 + conventional-changelog-angular: 6.0.0 + conventional-changelog-core: 5.0.1 + conventional-recommended-bump: 7.0.1 + cosmiconfig: ^8.2.0 + dedent: 0.7.0 + envinfo: 7.8.1 + execa: 5.0.0 + fs-extra: ^11.1.1 + get-port: 5.1.1 + get-stream: 6.0.0 + git-url-parse: 13.1.0 + glob-parent: 5.1.2 + globby: 11.1.0 + graceful-fs: 4.2.11 + has-unicode: 2.0.1 + import-local: 3.1.0 + ini: ^1.3.8 + init-package-json: 5.0.0 + inquirer: ^8.2.4 + is-ci: 3.0.1 + is-stream: 2.0.0 + jest-diff: ">=29.4.3 < 30" + js-yaml: 4.1.0 + libnpmaccess: 7.0.2 + libnpmpublish: 7.3.0 + load-json-file: 6.2.0 + lodash: ^4.17.21 + make-dir: 3.1.0 + minimatch: 3.0.5 + multimatch: 5.0.0 + node-fetch: 2.6.7 + npm-package-arg: 8.1.1 + npm-packlist: 5.1.1 + npm-registry-fetch: ^14.0.5 + npmlog: ^6.0.2 + nx: ">=16.5.1 < 17" + p-map: 4.0.0 + p-map-series: 2.1.0 + p-pipe: 3.1.0 + p-queue: 6.6.2 + p-reduce: 2.1.0 + p-waterfall: 2.1.1 + pacote: ^15.2.0 + pify: 5.0.0 + read-cmd-shim: 4.0.0 + read-package-json: 6.0.4 + resolve-from: 5.0.0 + rimraf: ^4.4.1 + semver: ^7.3.8 + signal-exit: 3.0.7 + slash: 3.0.0 + ssri: ^9.0.1 + strong-log-transformer: 2.1.0 + tar: 6.1.11 + temp-dir: 1.0.0 + typescript: ">=3 < 6" + upath: 2.0.1 + uuid: ^9.0.0 + validate-npm-package-license: 3.0.4 + validate-npm-package-name: 5.0.0 + write-file-atomic: 5.0.1 + write-pkg: 4.0.0 + yargs: 16.2.0 + yargs-parser: 20.2.4 + bin: + lerna: dist/cli.js + checksum: 5abd20dd13cfc770e1ca0c0915f5c1c820e08824379dabffc27376684f386d1aa43036294aa252106b25acd5ac20dbcf8a535eb4e59b783d60fcae7783eeacf4 + languageName: node + linkType: hard + +"leven@npm:^3.1.0": + version: 3.1.0 + resolution: "leven@npm:3.1.0" + checksum: 638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 + languageName: node + linkType: hard + +"levn@npm:^0.4.1": + version: 0.4.1 + resolution: "levn@npm:0.4.1" + dependencies: + prelude-ls: ^1.2.1 + type-check: ~0.4.0 + checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4 + languageName: node + linkType: hard + +"levn@npm:~0.3.0": + version: 0.3.0 + resolution: "levn@npm:0.3.0" + dependencies: + prelude-ls: ~1.1.2 + type-check: ~0.3.2 + checksum: 0d084a524231a8246bb10fec48cdbb35282099f6954838604f3c7fc66f2e16fa66fd9cc2f3f20a541a113c4dafdf181e822c887c8a319c9195444e6c64ac395e + languageName: node + linkType: hard + +"lib0@npm:^0.2.42, lib0@npm:^0.2.49": + version: 0.2.65 + resolution: "lib0@npm:0.2.65" + dependencies: + isomorphic.js: ^0.2.4 + bin: + 0gentesthtml: bin/gentesthtml.js + checksum: c511810d209d8b616005ff9a93966d11c15b0a092953c1fb01f48dd53fb9830d19cbfe7dfffaa3f5913fba5801761fba76e3ca4dae8c2164cb606428a5f6a838 + languageName: node + linkType: hard + +"libnpmaccess@npm:7.0.2": + version: 7.0.2 + resolution: "libnpmaccess@npm:7.0.2" + dependencies: + npm-package-arg: ^10.1.0 + npm-registry-fetch: ^14.0.3 + checksum: 73d49f39391173276c46c12e32f503709338efd867d255d062ae9bc9e9f464d61240747f42bdd6dc6003a5dc275a27352ebfc11ed4cb424091463f302d823f23 + languageName: node + linkType: hard + +"libnpmpublish@npm:7.3.0": + version: 7.3.0 + resolution: "libnpmpublish@npm:7.3.0" + dependencies: + ci-info: ^3.6.1 + normalize-package-data: ^5.0.0 + npm-package-arg: ^10.1.0 + npm-registry-fetch: ^14.0.3 + proc-log: ^3.0.0 + semver: ^7.3.7 + sigstore: ^1.4.0 + ssri: ^10.0.1 + checksum: 03bedb65eb2293cfe5039f925ec1041deea698c5ac802bb74f6a0d44ee70529c38c32eea7c722f3a1f1219b54314021ad7f4764f93b66d619bea62ce0759faa0 + languageName: node + linkType: hard + +"license-webpack-plugin@npm:^2.3.14": + version: 2.3.21 + resolution: "license-webpack-plugin@npm:2.3.21" + dependencies: + "@types/webpack-sources": ^0.1.5 + webpack-sources: ^1.2.0 + peerDependenciesMeta: + webpack: + optional: true + checksum: 6208bd2060d200fbffbcc89702c929d50c5a4a3f2158b046cf813b3f7f728bbbe4611b9fea2d67843bb5e7d64ad9122cc368a19ac73f5c4ad41765e6283bdc0c + languageName: node + linkType: hard + +"license-webpack-plugin@npm:^4.0.2": + version: 4.0.2 + resolution: "license-webpack-plugin@npm:4.0.2" + dependencies: + webpack-sources: ^3.0.0 + peerDependenciesMeta: + webpack: + optional: true + webpack-sources: + optional: true + checksum: e88ebdb9c8bdfc0926dd7211d7fe2ee8697a44bb00a96bb5e6ca844b6acb7d24dd54eb17ec485e2e0140c3cc86709d1c2bd46e091ab52af076e1e421054c8322 + languageName: node + linkType: hard + +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 + languageName: node + linkType: hard + +"lines-and-columns@npm:~2.0.3": + version: 2.0.3 + resolution: "lines-and-columns@npm:2.0.3" + checksum: 5955363dfd7d3d7c476d002eb47944dbe0310d57959e2112dce004c0dc76cecfd479cf8c098fd479ff344acdf04ee0e82b455462a26492231ac152f6c48d17a1 + languageName: node + linkType: hard + +"load-json-file@npm:6.2.0": + version: 6.2.0 + resolution: "load-json-file@npm:6.2.0" + dependencies: + graceful-fs: ^4.1.15 + parse-json: ^5.0.0 + strip-bom: ^4.0.0 + type-fest: ^0.6.0 + checksum: 4429e430ebb99375fc7cd936348e4f7ba729486080ced4272091c1e386a7f5f738ea3337d8ffd4b01c2f5bc3ddde92f2c780045b66838fe98bdb79f901884643 + languageName: node + linkType: hard + +"load-json-file@npm:^4.0.0": + version: 4.0.0 + resolution: "load-json-file@npm:4.0.0" + dependencies: + graceful-fs: ^4.1.2 + parse-json: ^4.0.0 + pify: ^3.0.0 + strip-bom: ^3.0.0 + checksum: 8f5d6d93ba64a9620445ee9bde4d98b1eac32cf6c8c2d20d44abfa41a6945e7969456ab5f1ca2fb06ee32e206c9769a20eec7002fe290de462e8c884b6b8b356 + languageName: node + linkType: hard + +"loader-runner@npm:^4.2.0": + version: 4.3.0 + resolution: "loader-runner@npm:4.3.0" + checksum: a90e00dee9a16be118ea43fec3192d0b491fe03a32ed48a4132eb61d498f5536a03a1315531c19d284392a8726a4ecad71d82044c28d7f22ef62e029bf761569 + languageName: node + linkType: hard + +"loader-utils@npm:^2.0.0": + version: 2.0.4 + resolution: "loader-utils@npm:2.0.4" + dependencies: + big.js: ^5.2.2 + emojis-list: ^3.0.0 + json5: ^2.1.2 + checksum: a5281f5fff1eaa310ad5e1164095689443630f3411e927f95031ab4fb83b4a98f388185bb1fe949e8ab8d4247004336a625e9255c22122b815bb9a4c5d8fc3b7 + languageName: node + linkType: hard + +"locate-path@npm:^2.0.0": + version: 2.0.0 + resolution: "locate-path@npm:2.0.0" + dependencies: + p-locate: ^2.0.0 + path-exists: ^3.0.0 + checksum: 02d581edbbbb0fa292e28d96b7de36b5b62c2fa8b5a7e82638ebb33afa74284acf022d3b1e9ae10e3ffb7658fbc49163fcd5e76e7d1baaa7801c3e05a81da755 + languageName: node + linkType: hard + +"locate-path@npm:^5.0.0": + version: 5.0.0 + resolution: "locate-path@npm:5.0.0" + dependencies: + p-locate: ^4.1.0 + checksum: 83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 + languageName: node + linkType: hard + +"locate-path@npm:^6.0.0": + version: 6.0.0 + resolution: "locate-path@npm:6.0.0" + dependencies: + p-locate: ^5.0.0 + checksum: 72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a + languageName: node + linkType: hard + +"lockfile@npm:1.0.4": + version: 1.0.4 + resolution: "lockfile@npm:1.0.4" + dependencies: + signal-exit: ^3.0.2 + checksum: 8de35aace8acbe883cbca3cc3959e88904d57c79dccd4afffc64aea8f9cf7b4c63598d08b8add66fbf381f8fb3ce4fd4c518cd231c797c266b6c790eb7b33abc + languageName: node + linkType: hard + +"lodash-es@npm:^4.17.15, lodash-es@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash-es@npm:4.17.21" + checksum: 05cbffad6e2adbb331a4e16fbd826e7faee403a1a04873b82b42c0f22090f280839f85b95393f487c1303c8a3d2a010048bf06151a6cbe03eee4d388fb0a12d2 + languageName: node + linkType: hard + +"lodash.curry@npm:^4.1.1": + version: 4.1.1 + resolution: "lodash.curry@npm:4.1.1" + checksum: 9192b70fe7df4d1ff780c0260bee271afa9168c93fe4fa24bc861900240531b59781b5fdaadf4644fea8f4fbcd96f0700539ab294b579ffc1022c6c15dcc462a + languageName: node + linkType: hard + +"lodash.debounce@npm:^4.0.8": + version: 4.0.8 + resolution: "lodash.debounce@npm:4.0.8" + checksum: a3f527d22c548f43ae31c861ada88b2637eb48ac6aa3eb56e82d44917971b8aa96fbb37aa60efea674dc4ee8c42074f90f7b1f772e9db375435f6c83a19b3bc6 + languageName: node + linkType: hard + +"lodash.escape@npm:^4.0.1": + version: 4.0.1 + resolution: "lodash.escape@npm:4.0.1" + checksum: fcb54f457497256964d619d5cccbd80a961916fca60df3fe0fa3e7f052715c2944c0ed5aefb4f9e047d127d44aa2d55555f3350cb42c6549e9e293fb30b41e7f + languageName: node + linkType: hard + +"lodash.ismatch@npm:^4.4.0": + version: 4.4.0 + resolution: "lodash.ismatch@npm:4.4.0" + checksum: a393917578842705c7fc1a30fb80613d1ac42d20b67eb26a2a6004d6d61ee90b419f9eb320508ddcd608e328d91eeaa2651411727eaa9a12534ed6ccb02fc705 + languageName: node + linkType: hard + +"lodash.memoize@npm:4.x": + version: 4.1.2 + resolution: "lodash.memoize@npm:4.1.2" + checksum: 9ff3942feeccffa4f1fafa88d32f0d24fdc62fd15ded5a74a5f950ff5f0c6f61916157246744c620173dddf38d37095a92327d5fd3861e2063e736a5c207d089 + languageName: node + linkType: hard + +"lodash.merge@npm:^4.6.2": + version: 4.6.2 + resolution: "lodash.merge@npm:4.6.2" + checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 + languageName: node + linkType: hard + +"lodash.mergewith@npm:^4.6.1": + version: 4.6.2 + resolution: "lodash.mergewith@npm:4.6.2" + checksum: a6db2a9339752411f21b956908c404ec1e088e783a65c8b29e30ae5b3b6384f82517662d6f425cc97c2070b546cc2c7daaa8d33f78db7b6e9be06cd834abdeb8 + languageName: node + linkType: hard + +"lodash.truncate@npm:^4.4.2": + version: 4.4.2 + resolution: "lodash.truncate@npm:4.4.2" + checksum: b463d8a382cfb5f0e71c504dcb6f807a7bd379ff1ea216669aa42c52fc28c54e404bfbd96791aa09e6df0de2c1d7b8f1b7f4b1a61f324d38fe98bc535aeee4f5 + languageName: node + linkType: hard + +"lodash@npm:4, lodash@npm:4.17.21, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.7.0": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 + languageName: node + linkType: hard + +"log-symbols@npm:^4.1.0": + version: 4.1.0 + resolution: "log-symbols@npm:4.1.0" + dependencies: + chalk: ^4.1.0 + is-unicode-supported: ^0.1.0 + checksum: fce1497b3135a0198803f9f07464165e9eb83ed02ceb2273930a6f8a508951178d8cf4f0378e9d28300a2ed2bc49050995d2bd5f53ab716bb15ac84d58c6ef74 + languageName: node + linkType: hard + +"log-symbols@npm:^5.1.0": + version: 5.1.0 + resolution: "log-symbols@npm:5.1.0" + dependencies: + chalk: ^5.0.0 + is-unicode-supported: ^1.1.0 + checksum: 7291b6e7f1b3df6865bdaeb9b59605c832668ac2fa0965c63b1e7dd3700349aec09c1d7d40c368d5041ff58b7f89461a56e4009471921301af7b3609cbff9a29 + languageName: node + linkType: hard + +"loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: ^3.0.0 || ^4.0.0 + bin: + loose-envify: cli.js + checksum: 6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 + languageName: node + linkType: hard + +"lowdb@npm:1.0.0": + version: 1.0.0 + resolution: "lowdb@npm:1.0.0" + dependencies: + graceful-fs: ^4.1.3 + is-promise: ^2.1.0 + lodash: 4 + pify: ^3.0.0 + steno: ^0.4.1 + checksum: 7ae89e3d6e00963129f72c4d4e1fe8e4cda5c08a46b4f4e525109483147e799df90c07d95aeced1c270cc10f4a24c6660fe1601cc4b3a6e2c3f922ad64517eab + languageName: node + linkType: hard + +"lower-case@npm:^2.0.2": + version: 2.0.2 + resolution: "lower-case@npm:2.0.2" + dependencies: + tslib: ^2.0.3 + checksum: 83a0a5f159ad7614bee8bf976b96275f3954335a84fad2696927f609ddae902802c4f3312d86668722e668bef41400254807e1d3a7f2e8c3eede79691aa1f010 + languageName: node + linkType: hard + +"lowercase-keys@npm:^2.0.0": + version: 2.0.0 + resolution: "lowercase-keys@npm:2.0.0" + checksum: 24d7ebd56ccdf15ff529ca9e08863f3c54b0b9d1edb97a3ae1af34940ae666c01a1e6d200707bce730a8ef76cb57cc10e65f245ecaaf7e6bc8639f2fb460ac23 + languageName: node + linkType: hard + +"lru-cache@npm:7.18.3, lru-cache@npm:^7.4.4, lru-cache@npm:^7.5.1, lru-cache@npm:^7.7.1": + version: 7.18.3 + resolution: "lru-cache@npm:7.18.3" + checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 + languageName: node + linkType: hard + +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: ^3.0.2 + checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb + languageName: node + linkType: hard + +"lru-cache@npm:^6.0.0": + version: 6.0.0 + resolution: "lru-cache@npm:6.0.0" + dependencies: + yallist: ^4.0.0 + checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 + languageName: node + linkType: hard + +"lru-cache@npm:^9.1.1": + version: 9.1.2 + resolution: "lru-cache@npm:9.1.2" + checksum: d3415634be3908909081fc4c56371a8d562d9081eba70543d86871b978702fffd0e9e362b83921b27a29ae2b37b90f55675aad770a54ac83bb3e4de5049d4b15 + languageName: node + linkType: hard + +"lru-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "lru-queue@npm:0.1.0" + dependencies: + es5-ext: ~0.10.2 + checksum: 7f2c53c5e7f2de20efb6ebb3086b7aea88d6cf9ae91ac5618ece974122960c4e8ed04988e81d92c3e63d60b12c556b14d56ef7a9c5a4627b23859b813e39b1a2 + languageName: node + linkType: hard + +"lunr@npm:^2.3.9": + version: 2.3.9 + resolution: "lunr@npm:2.3.9" + checksum: 176719e24fcce7d3cf1baccce9dd5633cd8bdc1f41ebe6a180112e5ee99d80373fe2454f5d4624d437e5a8319698ca6837b9950566e15d2cae5f2a543a3db4b8 + languageName: node + linkType: hard + +"make-dir@npm:3.1.0, make-dir@npm:^3.0.0, make-dir@npm:^3.1.0": + version: 3.1.0 + resolution: "make-dir@npm:3.1.0" + dependencies: + semver: ^6.0.0 + checksum: 484200020ab5a1fdf12f393fe5f385fc8e4378824c940fba1729dcd198ae4ff24867bc7a5646331e50cead8abff5d9270c456314386e629acec6dff4b8016b78 + languageName: node + linkType: hard + +"make-dir@npm:^2.1.0": + version: 2.1.0 + resolution: "make-dir@npm:2.1.0" + dependencies: + pify: ^4.0.1 + semver: ^5.6.0 + checksum: 043548886bfaf1820323c6a2997e6d2fa51ccc2586ac14e6f14634f7458b4db2daf15f8c310e2a0abd3e0cddc64df1890d8fc7263033602c47bb12cbfcf86aab + languageName: node + linkType: hard + +"make-error@npm:1.x": + version: 1.3.6 + resolution: "make-error@npm:1.3.6" + checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 + languageName: node + linkType: hard + +"make-fetch-happen@npm:^10.0.3": + version: 10.2.1 + resolution: "make-fetch-happen@npm:10.2.1" + dependencies: + agentkeepalive: ^4.2.1 + cacache: ^16.1.0 + http-cache-semantics: ^4.1.0 + http-proxy-agent: ^5.0.0 + https-proxy-agent: ^5.0.0 + is-lambda: ^1.0.1 + lru-cache: ^7.7.1 + minipass: ^3.1.6 + minipass-collect: ^1.0.2 + minipass-fetch: ^2.0.3 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + negotiator: ^0.6.3 + promise-retry: ^2.0.1 + socks-proxy-agent: ^7.0.0 + ssri: ^9.0.0 + checksum: 2332eb9a8ec96f1ffeeea56ccefabcb4193693597b132cd110734d50f2928842e22b84cfa1508e921b8385cdfd06dda9ad68645fed62b50fff629a580f5fb72c + languageName: node + linkType: hard + +"make-fetch-happen@npm:^11.0.0, make-fetch-happen@npm:^11.0.1, make-fetch-happen@npm:^11.1.1": + version: 11.1.1 + resolution: "make-fetch-happen@npm:11.1.1" + dependencies: + agentkeepalive: ^4.2.1 + cacache: ^17.0.0 + http-cache-semantics: ^4.1.1 + http-proxy-agent: ^5.0.0 + https-proxy-agent: ^5.0.0 + is-lambda: ^1.0.1 + lru-cache: ^7.7.1 + minipass: ^5.0.0 + minipass-fetch: ^3.0.0 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + negotiator: ^0.6.3 + promise-retry: ^2.0.1 + socks-proxy-agent: ^7.0.0 + ssri: ^10.0.0 + checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 + languageName: node + linkType: hard + +"makeerror@npm:1.0.12": + version: 1.0.12 + resolution: "makeerror@npm:1.0.12" + dependencies: + tmpl: 1.0.5 + checksum: b38a025a12c8146d6eeea5a7f2bf27d51d8ad6064da8ca9405fcf7bf9b54acd43e3b30ddd7abb9b1bfa4ddb266019133313482570ddb207de568f71ecfcf6060 + languageName: node + linkType: hard + +"map-obj@npm:^1.0.0": + version: 1.0.1 + resolution: "map-obj@npm:1.0.1" + checksum: 9949e7baec2a336e63b8d4dc71018c117c3ce6e39d2451ccbfd3b8350c547c4f6af331a4cbe1c83193d7c6b786082b6256bde843db90cb7da2a21e8fcc28afed + languageName: node + linkType: hard + +"map-obj@npm:^4.0.0, map-obj@npm:^4.1.0": + version: 4.3.0 + resolution: "map-obj@npm:4.3.0" + checksum: fbc554934d1a27a1910e842bc87b177b1a556609dd803747c85ece420692380827c6ae94a95cce4407c054fa0964be3bf8226f7f2cb2e9eeee432c7c1985684e + languageName: node + linkType: hard + +"markdown-to-jsx@npm:^7.1.9": + version: 7.1.9 + resolution: "markdown-to-jsx@npm:7.1.9" + peerDependencies: + react: ">= 0.14.0" + checksum: 81ab9bd0ad93d4e90c39a67a4df2cc2d3b24579f8f018852f05abce442b246cee9cd705ea9d01304144729a48c972b8b535d40a33e04a0a05d5073958e96ae76 + languageName: node + linkType: hard + +"marked@npm:^4.0.17, marked@npm:^4.3.0": + version: 4.3.0 + resolution: "marked@npm:4.3.0" + bin: + marked: bin/marked.js + checksum: 0db6817893952c3ec710eb9ceafb8468bf5ae38cb0f92b7b083baa13d70b19774674be04db5b817681fa7c5c6a088f61300815e4dd75a59696f4716ad69f6260 + languageName: node + linkType: hard + +"mathjax-full@npm:^3.2.2": + version: 3.2.2 + resolution: "mathjax-full@npm:3.2.2" + dependencies: + esm: ^3.2.25 + mhchemparser: ^4.1.0 + mj-context-menu: ^0.6.1 + speech-rule-engine: ^4.0.6 + checksum: 6fbccb9338e1fbf686202d924666d79ac9eb658157c1c8102ba018672188978c4cacfb1b6f65adf7d2d51dc79535ff3e32ba86b15e66d3011dda2ab99562d90d + languageName: node + linkType: hard + +"mathml-tag-names@npm:^2.1.3": + version: 2.1.3 + resolution: "mathml-tag-names@npm:2.1.3" + checksum: 1201a25a137d6b9e328facd67912058b8b45b19a6c4cc62641c9476195da28a275ca6e0eca070af5378b905c2b11abc1114676ba703411db0b9ce007de921ad0 + languageName: node + linkType: hard + +"mdn-data@npm:2.0.28": + version: 2.0.28 + resolution: "mdn-data@npm:2.0.28" + checksum: f51d587a6ebe8e426c3376c74ea6df3e19ec8241ed8e2466c9c8a3904d5d04397199ea4f15b8d34d14524b5de926d8724ae85207984be47e165817c26e49e0aa + languageName: node + linkType: hard + +"mdn-data@npm:2.0.30": + version: 2.0.30 + resolution: "mdn-data@npm:2.0.30" + checksum: d6ac5ac7439a1607df44b22738ecf83f48e66a0874e4482d6424a61c52da5cde5750f1d1229b6f5fa1b80a492be89465390da685b11f97d62b8adcc6e88189aa + languageName: node + linkType: hard + +"media-typer@npm:0.3.0": + version: 0.3.0 + resolution: "media-typer@npm:0.3.0" + checksum: af1b38516c28ec95d6b0826f6c8f276c58aec391f76be42aa07646b4e39d317723e869700933ca6995b056db4b09a78c92d5440dc23657e6764be5d28874bba1 + languageName: node + linkType: hard + +"memoize-one@npm:^4.0.0": + version: 4.0.3 + resolution: "memoize-one@npm:4.0.3" + checksum: addd18c046542f57440ba70bf8ebd48663d17626cade681f777522ef70900a87ec72c5041bed8ece4f6d40a2cb58803bae388b50a4b740d64f36bcda20c147b7 + languageName: node + linkType: hard + +"memoizee@npm:^0.4.14": + version: 0.4.15 + resolution: "memoizee@npm:0.4.15" + dependencies: + d: ^1.0.1 + es5-ext: ^0.10.53 + es6-weak-map: ^2.0.3 + event-emitter: ^0.3.5 + is-promise: ^2.2.2 + lru-queue: ^0.1.0 + next-tick: ^1.1.0 + timers-ext: ^0.1.7 + checksum: 4065d94416dbadac56edf5947bf342beca0e9f051f33ad60d7c4baf3f6ca0f3c6fdb770c5caed5a89c0ceaf9121428582f396445d591785281383d60aa883418 + languageName: node + linkType: hard + +"meow@npm:^10.1.5": + version: 10.1.5 + resolution: "meow@npm:10.1.5" + dependencies: + "@types/minimist": ^1.2.2 + camelcase-keys: ^7.0.0 + decamelize: ^5.0.0 + decamelize-keys: ^1.1.0 + hard-rejection: ^2.1.0 + minimist-options: 4.1.0 + normalize-package-data: ^3.0.2 + read-pkg-up: ^8.0.0 + redent: ^4.0.0 + trim-newlines: ^4.0.2 + type-fest: ^1.2.2 + yargs-parser: ^20.2.9 + checksum: dd5f0caa4af18517813547dc66741dcbf52c4c23def5062578d39b11189fd9457aee5c1f2263a5cd6592a465023df8357e8ac876b685b64dbcf545e3f66c23a7 + languageName: node + linkType: hard + +"meow@npm:^8.1.2": + version: 8.1.2 + resolution: "meow@npm:8.1.2" + dependencies: + "@types/minimist": ^1.2.0 + camelcase-keys: ^6.2.2 + decamelize-keys: ^1.1.0 + hard-rejection: ^2.1.0 + minimist-options: 4.1.0 + normalize-package-data: ^3.0.0 + read-pkg-up: ^7.0.1 + redent: ^3.0.0 + trim-newlines: ^3.0.0 + type-fest: ^0.18.0 + yargs-parser: ^20.2.3 + checksum: bc23bf1b4423ef6a821dff9734406bce4b91ea257e7f10a8b7f896f45b59649f07adc0926e2917eacd8cf1df9e4cd89c77623cf63dfd0f8bf54de07a32ee5a85 + languageName: node + linkType: hard + +"merge-descriptors@npm:1.0.1": + version: 1.0.1 + resolution: "merge-descriptors@npm:1.0.1" + checksum: 5abc259d2ae25bb06d19ce2b94a21632583c74e2a9109ee1ba7fd147aa7362b380d971e0251069f8b3eb7d48c21ac839e21fa177b335e82c76ec172e30c31a26 + languageName: node + linkType: hard + +"merge-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-stream@npm:2.0.0" + checksum: 6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 + languageName: node + linkType: hard + +"merge2@npm:^1.2.3, merge2@npm:^1.3.0, merge2@npm:^1.4.1": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 + languageName: node + linkType: hard + +"methods@npm:~1.1.2": + version: 1.1.2 + resolution: "methods@npm:1.1.2" + checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a + languageName: node + linkType: hard + +"mhchemparser@npm:^4.1.0": + version: 4.1.1 + resolution: "mhchemparser@npm:4.1.1" + checksum: a030ffa351b234385028498537a93a15f2b5542338678391639632498c98e2c771719f2c3b3645ee6d1338f602f087a87f96e8d85bfe5296b27eb9bdd6664fd9 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": + version: 4.0.5 + resolution: "micromatch@npm:4.0.5" + dependencies: + braces: ^3.0.2 + picomatch: ^2.3.1 + checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc + languageName: node + linkType: hard + +"mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f + languageName: node + linkType: hard + +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: 1.52.0 + checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 + languageName: node + linkType: hard + +"mime@npm:1.6.0": + version: 1.6.0 + resolution: "mime@npm:1.6.0" + bin: + mime: cli.js + checksum: fef25e39263e6d207580bdc629f8872a3f9772c923c7f8c7e793175cee22777bbe8bba95e5d509a40aaa292d8974514ce634ae35769faa45f22d17edda5e8557 + languageName: node + linkType: hard + +"mime@npm:2.6.0": + version: 2.6.0 + resolution: "mime@npm:2.6.0" + bin: + mime: cli.js + checksum: 1497ba7b9f6960694268a557eae24b743fd2923da46ec392b042469f4b901721ba0adcf8b0d3c2677839d0e243b209d76e5edcbd09cfdeffa2dfb6bb4df4b862 + languageName: node + linkType: hard + +"mime@npm:3.0.0": + version: 3.0.0 + resolution: "mime@npm:3.0.0" + bin: + mime: cli.js + checksum: f43f9b7bfa64534e6b05bd6062961681aeb406a5b53673b53b683f27fcc4e739989941836a355eef831f4478923651ecc739f4a5f6e20a76487b432bfd4db928 + languageName: node + linkType: hard + +"mimic-fn@npm:^2.1.0": + version: 2.1.0 + resolution: "mimic-fn@npm:2.1.0" + checksum: d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a + languageName: node + linkType: hard + +"mimic-fn@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-fn@npm:4.0.0" + checksum: 995dcece15ee29aa16e188de6633d43a3db4611bcf93620e7e62109ec41c79c0f34277165b8ce5e361205049766e371851264c21ac64ca35499acb5421c2ba56 + languageName: node + linkType: hard + +"mimic-response@npm:^1.0.0": + version: 1.0.1 + resolution: "mimic-response@npm:1.0.1" + checksum: 034c78753b0e622bc03c983663b1cdf66d03861050e0c8606563d149bc2b02d63f62ce4d32be4ab50d0553ae0ffe647fc34d1f5281184c6e1e8cf4d85e8d9823 + languageName: node + linkType: hard + +"mimic-response@npm:^2.0.0": + version: 2.1.0 + resolution: "mimic-response@npm:2.1.0" + checksum: 014fad6ab936657e5f2f48bd87af62a8e928ebe84472aaf9e14fec4fcb31257a5edff77324d8ac13ddc6685ba5135cf16e381efac324e5f174fb4ddbf902bf07 + languageName: node + linkType: hard + +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 25739fee32c17f433626bf19f016df9036b75b3d84a3046c7d156e72ec963dd29d7fc8a302f55a3d6c5a4ff24259676b15d915aad6480815a969ff2ec0836867 + languageName: node + linkType: hard + +"min-indent@npm:^1.0.0, min-indent@npm:^1.0.1": + version: 1.0.1 + resolution: "min-indent@npm:1.0.1" + checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 + languageName: node + linkType: hard + +"mini-css-extract-plugin@npm:^2.7.0": + version: 2.7.3 + resolution: "mini-css-extract-plugin@npm:2.7.3" + dependencies: + schema-utils: ^4.0.0 + peerDependencies: + webpack: ^5.0.0 + checksum: 9f3a25c1298280d40e56552e5cfd7f84fea25ddd8530bd8ecfd6b08caffe59a1c55c020f1f3c8beb7c04f5e92ce71ed43a52a72deed5570c686316348f13b6f4 + languageName: node + linkType: hard + +"mini-svg-data-uri@npm:^1.4.4": + version: 1.4.4 + resolution: "mini-svg-data-uri@npm:1.4.4" + bin: + mini-svg-data-uri: cli.js + checksum: 997f1fbd8d59a70f03761e18626d335197a3479cb9d1ff75678e4b64b864d32a0b8fc18115eabde035e5299b8b4a354a78e57dd6ac10f9d604162a6170898d09 + languageName: node + linkType: hard + +"minimatch@npm:2 || 3, minimatch@npm:3.1.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: ^1.1.7 + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a + languageName: node + linkType: hard + +"minimatch@npm:3.0.5, minimatch@npm:~3.0.4": + version: 3.0.5 + resolution: "minimatch@npm:3.0.5" + dependencies: + brace-expansion: ^1.1.7 + checksum: a3b84b426eafca947741b864502cee02860c4e7b145de11ad98775cfcf3066fef422583bc0ffce0952ddf4750c1ccf4220b1556430d4ce10139f66247d87d69e + languageName: node + linkType: hard + +"minimatch@npm:^5.0.1": + version: 5.1.6 + resolution: "minimatch@npm:5.1.6" + dependencies: + brace-expansion: ^2.0.1 + checksum: 7564208ef81d7065a370f788d337cd80a689e981042cb9a1d0e6580b6c6a8c9279eba80010516e258835a988363f99f54a6f711a315089b8b42694f5da9d0d77 + languageName: node + linkType: hard + +"minimatch@npm:^8.0.2": + version: 8.0.4 + resolution: "minimatch@npm:8.0.4" + dependencies: + brace-expansion: ^2.0.1 + checksum: 2e46cffb86bacbc524ad45a6426f338920c529dd13f3a732cc2cf7618988ee1aae88df4ca28983285aca9e0f45222019ac2d14ebd17c1edadd2ee12221ab801a + languageName: node + linkType: hard + +"minimatch@npm:^9.0.0, minimatch@npm:^9.0.1": + version: 9.0.2 + resolution: "minimatch@npm:9.0.2" + dependencies: + brace-expansion: ^2.0.1 + checksum: 2eb12e2047a062fdb973fb51b9803f2455e3a00977858c038d66646d303a5a15bbcbc6ed5a2fc403bc869b1309f829ed3acd881d3246faf044ea7a494974b924 + languageName: node + linkType: hard + +"minimist-options@npm:4.1.0": + version: 4.1.0 + resolution: "minimist-options@npm:4.1.0" + dependencies: + arrify: ^1.0.1 + is-plain-obj: ^1.1.0 + kind-of: ^6.0.3 + checksum: 8c040b3068811e79de1140ca2b708d3e203c8003eb9a414c1ab3cd467fc5f17c9ca02a5aef23bedc51a7f8bfbe77f87e9a7e31ec81fba304cda675b019496f4e + languageName: node + linkType: hard + +"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:~1.2.0": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 + languageName: node + linkType: hard + +"minipass-collect@npm:^1.0.2": + version: 1.0.2 + resolution: "minipass-collect@npm:1.0.2" + dependencies: + minipass: ^3.0.0 + checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 + languageName: node + linkType: hard + +"minipass-fetch@npm:^2.0.3": + version: 2.1.2 + resolution: "minipass-fetch@npm:2.1.2" + dependencies: + encoding: ^0.1.13 + minipass: ^3.1.6 + minipass-sized: ^1.0.3 + minizlib: ^2.1.2 + dependenciesMeta: + encoding: + optional: true + checksum: 3f216be79164e915fc91210cea1850e488793c740534985da017a4cbc7a5ff50506956d0f73bb0cb60e4fe91be08b6b61ef35101706d3ef5da2c8709b5f08f91 + languageName: node + linkType: hard + +"minipass-fetch@npm:^3.0.0": + version: 3.0.3 + resolution: "minipass-fetch@npm:3.0.3" + dependencies: + encoding: ^0.1.13 + minipass: ^5.0.0 + minipass-sized: ^1.0.3 + minizlib: ^2.1.2 + dependenciesMeta: + encoding: + optional: true + checksum: af5ab2552a16fcf505d35fd7ffb84b57f4a0eeb269e6e1d9a2a75824dda48b36e527083250b7cca4a4def21d9544e2ade441e4730e233c0bc2133f6abda31e18 + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: ^3.0.0 + checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf + languageName: node + linkType: hard + +"minipass-json-stream@npm:^1.0.1": + version: 1.0.1 + resolution: "minipass-json-stream@npm:1.0.1" + dependencies: + jsonparse: ^1.3.1 + minipass: ^3.0.0 + checksum: 791b696a27d1074c4c08dab1bf5a9f3201145c2933e428f45d880467bce12c60de4703203d2928de4b162d0ae77b0bb4b55f96cb846645800aa0eb4919b3e796 + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: ^3.0.0 + checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b + languageName: node + linkType: hard + +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: ^3.0.0 + checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 + languageName: node + linkType: hard + +"minipass@npm:^3.0.0, minipass@npm:^3.1.1, minipass@npm:^3.1.6": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: ^4.0.0 + checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 + languageName: node + linkType: hard + +"minipass@npm:^4.2.4": + version: 4.2.8 + resolution: "minipass@npm:4.2.8" + checksum: 7f4914d5295a9a30807cae5227a37a926e6d910c03f315930fde52332cf0575dfbc20295318f91f0baf0e6bb11a6f668e30cde8027dea7a11b9d159867a3c830 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0, minipass@npm:^5.0.0 || ^6.0.2": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea + languageName: node + linkType: hard + +"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: ^3.0.0 + yallist: ^4.0.0 + checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 + languageName: node + linkType: hard + +"mj-context-menu@npm:^0.6.1": + version: 0.6.1 + resolution: "mj-context-menu@npm:0.6.1" + checksum: 7a036026538662cac9619b760fade98681618c3ddf417cb36eddb7c28a937baf257c56fd0b6318738419e738ba01a00bcb3790b324885fd6edbae03fb0a2c986 + languageName: node + linkType: hard + +"mkdirp@npm:1.0.4, mkdirp@npm:^1.0.3, mkdirp@npm:^1.0.4": + version: 1.0.4 + resolution: "mkdirp@npm:1.0.4" + bin: + mkdirp: bin/cmd.js + checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f + languageName: node + linkType: hard + +"mkdirp@npm:^0.5.1, mkdirp@npm:~0.5.1": + version: 0.5.6 + resolution: "mkdirp@npm:0.5.6" + dependencies: + minimist: ^1.2.6 + bin: + mkdirp: bin/cmd.js + checksum: 0c91b721bb12c3f9af4b77ebf73604baf350e64d80df91754dc509491ae93bf238581e59c7188360cec7cb62fc4100959245a42cfe01834efedc5e9d068376c2 + languageName: node + linkType: hard + +"modify-values@npm:^1.0.1": + version: 1.0.1 + resolution: "modify-values@npm:1.0.1" + checksum: 8296610c608bc97b03c2cf889c6cdf4517e32fa2d836440096374c2209f6b7b3e256c209493a0b32584b9cb32d528e99d0dd19dcd9a14d2d915a312d391cc7e9 + languageName: node + linkType: hard + +"mrmime@npm:^1.0.0": + version: 1.0.1 + resolution: "mrmime@npm:1.0.1" + checksum: cc979da44bbbffebaa8eaf7a45117e851f2d4cb46a3ada6ceb78130466a04c15a0de9a9ce1c8b8ba6f6e1b8618866b1352992bf1757d241c0ddca558b9f28a77 + languageName: node + linkType: hard + +"ms@npm:2.0.0": + version: 2.0.0 + resolution: "ms@npm:2.0.0" + checksum: 0e6a22b8b746d2e0b65a430519934fefd41b6db0682e3477c10f60c76e947c4c0ad06f63ffdf1d78d335f83edee8c0aa928aa66a36c7cd95b69b26f468d527f4 + languageName: node + linkType: hard + +"ms@npm:2.1.2": + version: 2.1.2 + resolution: "ms@npm:2.1.2" + checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f + languageName: node + linkType: hard + +"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d + languageName: node + linkType: hard + +"multimatch@npm:5.0.0": + version: 5.0.0 + resolution: "multimatch@npm:5.0.0" + dependencies: + "@types/minimatch": ^3.0.3 + array-differ: ^3.0.0 + array-union: ^2.1.0 + arrify: ^2.0.1 + minimatch: ^3.0.4 + checksum: 82c8030a53af965cab48da22f1b0f894ef99e16ee680dabdfbd38d2dfacc3c8208c475203d747afd9e26db44118ed0221d5a0d65268c864f06d6efc7ac6df812 + languageName: node + linkType: hard + +"mute-stream@npm:0.0.8": + version: 0.0.8 + resolution: "mute-stream@npm:0.0.8" + checksum: ff48d251fc3f827e5b1206cda0ffdaec885e56057ee86a3155e1951bc940fd5f33531774b1cc8414d7668c10a8907f863f6561875ee6e8768931a62121a531a1 + languageName: node + linkType: hard + +"mute-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "mute-stream@npm:1.0.0" + checksum: 36fc968b0e9c9c63029d4f9dc63911950a3bdf55c9a87f58d3a266289b67180201cade911e7699f8b2fa596b34c9db43dad37649e3f7fdd13c3bb9edb0017ee7 + languageName: node + linkType: hard + +"mv@npm:2.1.1": + version: 2.1.1 + resolution: "mv@npm:2.1.1" + dependencies: + mkdirp: ~0.5.1 + ncp: ~2.0.0 + rimraf: ~2.4.0 + checksum: 59d4b5ebff6c265b452d6630ae8873d573c82e36fdc1ed9c34c7901a0bf2d3d357022f49db8e9bded127b743f709c7ef7befec249a2b3967578d649a8029aa06 + languageName: node + linkType: hard + +"mz@npm:^2.7.0": + version: 2.7.0 + resolution: "mz@npm:2.7.0" + dependencies: + any-promise: ^1.0.0 + object-assign: ^4.0.1 + thenify-all: ^1.0.0 + checksum: 8427de0ece99a07e9faed3c0c6778820d7543e3776f9a84d22cf0ec0a8eb65f6e9aee9c9d353ff9a105ff62d33a9463c6ca638974cc652ee8140cd1e35951c87 + languageName: node + linkType: hard + +"nan@npm:^2.17.0": + version: 2.17.0 + resolution: "nan@npm:2.17.0" + dependencies: + node-gyp: latest + checksum: ec609aeaf7e68b76592a3ba96b372aa7f5df5b056c1e37410b0f1deefbab5a57a922061e2c5b369bae9c7c6b5e6eecf4ad2dac8833a1a7d3a751e0a7c7f849ed + languageName: node + linkType: hard + +"nanoclone@npm:^0.2.1": + version: 0.2.1 + resolution: "nanoclone@npm:0.2.1" + checksum: 96b2954e22f70561f41e20d69856266c65583c2a441dae108f1dc71b716785d2c8038dac5f1d5e92b117aed3825f526b53139e2e5d6e6db8a77cfa35b3b8bf40 + languageName: node + linkType: hard + +"nanoid@npm:^3.3.4, nanoid@npm:^3.3.6": + version: 3.3.6 + resolution: "nanoid@npm:3.3.6" + bin: + nanoid: bin/nanoid.cjs + checksum: 7d0eda657002738aa5206107bd0580aead6c95c460ef1bdd0b1a87a9c7ae6277ac2e9b945306aaa5b32c6dcb7feaf462d0f552e7f8b5718abfc6ead5c94a71b3 + languageName: node + linkType: hard + +"natural-compare-lite@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare-lite@npm:1.4.0" + checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 + languageName: node + linkType: hard + +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d + languageName: node + linkType: hard + +"ncp@npm:~2.0.0": + version: 2.0.0 + resolution: "ncp@npm:2.0.0" + bin: + ncp: ./bin/ncp + checksum: ea9b19221da1d1c5529bdb9f8e85c9d191d156bcaae408cce5e415b7fbfd8744c288e792bd7faf1fe3b70fd44c74e22f0d43c39b209bc7ac1fb8016f70793a16 + languageName: node + linkType: hard + +"negotiator@npm:0.6.3, negotiator@npm:^0.6.3": + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 + languageName: node + linkType: hard + +"neo-async@npm:^2.6.0, neo-async@npm:^2.6.2": + version: 2.6.2 + resolution: "neo-async@npm:2.6.2" + checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 + languageName: node + linkType: hard + +"next-tick@npm:1, next-tick@npm:^1.1.0": + version: 1.1.0 + resolution: "next-tick@npm:1.1.0" + checksum: 83b5cf36027a53ee6d8b7f9c0782f2ba87f4858d977342bfc3c20c21629290a2111f8374d13a81221179603ffc4364f38374b5655d17b6a8f8a8c77bdea4fe8b + languageName: node + linkType: hard + +"no-case@npm:^3.0.4": + version: 3.0.4 + resolution: "no-case@npm:3.0.4" + dependencies: + lower-case: ^2.0.2 + tslib: ^2.0.3 + checksum: 0b2ebc113dfcf737d48dde49cfebf3ad2d82a8c3188e7100c6f375e30eafbef9e9124aadc3becef237b042fd5eb0aad2fd78669c20972d045bbe7fea8ba0be5c + languageName: node + linkType: hard + +"node-addon-api@npm:^3.2.1": + version: 3.2.1 + resolution: "node-addon-api@npm:3.2.1" + dependencies: + node-gyp: latest + checksum: 2369986bb0881ccd9ef6bacdf39550e07e089a9c8ede1cbc5fc7712d8e2faa4d50da0e487e333d4125f8c7a616c730131d1091676c9d499af1d74560756b4a18 + languageName: node + linkType: hard + +"node-example@workspace:packages/services/examples/node": + version: 0.0.0-use.local + resolution: "node-example@workspace:packages/services/examples/node" + dependencies: + "@jupyterlab/services": ^7.0.8 + rimraf: ~3.0.0 + ws: ^8.11.0 + languageName: unknown + linkType: soft + +"node-fetch@npm:2.6.7, node-fetch@npm:^2.6.0, node-fetch@npm:^2.6.7, node-fetch@npm:cjs": + version: 2.6.7 + resolution: "node-fetch@npm:2.6.7" + dependencies: + whatwg-url: ^5.0.0 + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: 8d816ffd1ee22cab8301c7756ef04f3437f18dace86a1dae22cf81db8ef29c0bf6655f3215cb0cdb22b420b6fe141e64b26905e7f33f9377a7fa59135ea3e10b + languageName: node + linkType: hard + +"node-gyp-build@npm:^4.3.0": + version: 4.6.0 + resolution: "node-gyp-build@npm:4.6.0" + bin: + node-gyp-build: bin.js + node-gyp-build-optional: optional.js + node-gyp-build-test: build-test.js + checksum: 25d78c5ef1f8c24291f4a370c47ba52fcea14f39272041a90a7894cd50d766f7c8cb8fb06c0f42bf6f69b204b49d9be3c8fc344aac09714d5bdb95965499eb15 + languageName: node + linkType: hard + +"node-gyp@npm:^9.0.0, node-gyp@npm:latest": + version: 9.3.1 + resolution: "node-gyp@npm:9.3.1" + dependencies: + env-paths: ^2.2.0 + glob: ^7.1.4 + graceful-fs: ^4.2.6 + make-fetch-happen: ^10.0.3 + nopt: ^6.0.0 + npmlog: ^6.0.0 + rimraf: ^3.0.2 + semver: ^7.3.5 + tar: ^6.1.2 + which: ^2.0.2 + bin: + node-gyp: bin/node-gyp.js + checksum: b860e9976fa645ca0789c69e25387401b4396b93c8375489b5151a6c55cf2640a3b6183c212b38625ef7c508994930b72198338e3d09b9d7ade5acc4aaf51ea7 + languageName: node + linkType: hard + +"node-int64@npm:^0.4.0": + version: 0.4.0 + resolution: "node-int64@npm:0.4.0" + checksum: d0b30b1ee6d961851c60d5eaa745d30b5c95d94bc0e74b81e5292f7c42a49e3af87f1eb9e89f59456f80645d679202537de751b7d72e9e40ceea40c5e449057e + languageName: node + linkType: hard + +"node-releases@npm:^2.0.8": + version: 2.0.10 + resolution: "node-releases@npm:2.0.10" + checksum: d784ecde25696a15d449c4433077f5cce620ed30a1656c4abf31282bfc691a70d9618bae6868d247a67914d1be5cc4fde22f65a05f4398cdfb92e0fc83cadfbc + languageName: node + linkType: hard + +"node.extend@npm:^2.0.0": + version: 2.0.2 + resolution: "node.extend@npm:2.0.2" + dependencies: + has: ^1.0.3 + is: ^3.2.1 + checksum: 1fe3a1ca7fc35392f169c8a46d889d07deb201bba3a20d17df23efab509698c9639737b0c235c9be772a34035e749bae5d477f74c9e26a1b67c78bd7d6dce8e4 + languageName: node + linkType: hard + +"nopt@npm:^5.0.0": + version: 5.0.0 + resolution: "nopt@npm:5.0.0" + dependencies: + abbrev: 1 + bin: + nopt: bin/nopt.js + checksum: d35fdec187269503843924e0114c0c6533fb54bbf1620d0f28b4b60ba01712d6687f62565c55cc20a504eff0fbe5c63e22340c3fad549ad40469ffb611b04f2f + languageName: node + linkType: hard + +"nopt@npm:^6.0.0": + version: 6.0.0 + resolution: "nopt@npm:6.0.0" + dependencies: + abbrev: ^1.0.0 + bin: + nopt: bin/nopt.js + checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + languageName: node + linkType: hard + +"normalize-package-data@npm:^2.3.2, normalize-package-data@npm:^2.5.0": + version: 2.5.0 + resolution: "normalize-package-data@npm:2.5.0" + dependencies: + hosted-git-info: ^2.1.4 + resolve: ^1.10.0 + semver: 2 || 3 || 4 || 5 + validate-npm-package-license: ^3.0.1 + checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 + languageName: node + linkType: hard + +"normalize-package-data@npm:^3.0.0, normalize-package-data@npm:^3.0.2, normalize-package-data@npm:^3.0.3": + version: 3.0.3 + resolution: "normalize-package-data@npm:3.0.3" + dependencies: + hosted-git-info: ^4.0.1 + is-core-module: ^2.5.0 + semver: ^7.3.4 + validate-npm-package-license: ^3.0.1 + checksum: bbcee00339e7c26fdbc760f9b66d429258e2ceca41a5df41f5df06cc7652de8d82e8679ff188ca095cad8eff2b6118d7d866af2b68400f74602fbcbce39c160a + languageName: node + linkType: hard + +"normalize-package-data@npm:^5.0.0": + version: 5.0.0 + resolution: "normalize-package-data@npm:5.0.0" + dependencies: + hosted-git-info: ^6.0.0 + is-core-module: ^2.8.1 + semver: ^7.3.5 + validate-npm-package-license: ^3.0.4 + checksum: a459f05eaf7c2b643c61234177f08e28064fde97da15800e3d3ac0404e28450d43ac46fc95fbf6407a9bf20af4c58505ad73458a912dc1517f8c1687b1d68c27 + languageName: node + linkType: hard + +"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": + version: 3.0.0 + resolution: "normalize-path@npm:3.0.0" + checksum: 88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 + languageName: node + linkType: hard + +"normalize-url@npm:^6.0.1": + version: 6.1.0 + resolution: "normalize-url@npm:6.1.0" + checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 + languageName: node + linkType: hard + +"npm-bundled@npm:^1.1.2": + version: 1.1.2 + resolution: "npm-bundled@npm:1.1.2" + dependencies: + npm-normalize-package-bin: ^1.0.1 + checksum: 6e599155ef28d0b498622f47f1ba189dfbae05095a1ed17cb3a5babf961e965dd5eab621f0ec6f0a98de774e5836b8f5a5ee639010d64f42850a74acec3d4d09 + languageName: node + linkType: hard + +"npm-bundled@npm:^3.0.0": + version: 3.0.0 + resolution: "npm-bundled@npm:3.0.0" + dependencies: + npm-normalize-package-bin: ^3.0.0 + checksum: 110859c2d6dcd7941dac0932a29171cbde123060486a4b6e897aaf5e025abeb3d9ffcdfe9e9271992e6396b2986c2c534f1029a45a7c196f1257fa244305dbf8 + languageName: node + linkType: hard + +"npm-install-checks@npm:^6.0.0": + version: 6.1.1 + resolution: "npm-install-checks@npm:6.1.1" + dependencies: + semver: ^7.1.1 + checksum: 8fb3ed05cfd3fdeb20d2fd22d45a89cd509afac3b05d188af7d9bcdf07ed745d1346943692782a4dca4c42b2c1fec34eb42fdf20e2ef8bb5b249fbb5a811ce3b + languageName: node + linkType: hard + +"npm-normalize-package-bin@npm:^1.0.1": + version: 1.0.1 + resolution: "npm-normalize-package-bin@npm:1.0.1" + checksum: ae7f15155a1e3ace2653f12ddd1ee8eaa3c84452fdfbf2f1943e1de264e4b079c86645e2c55931a51a0a498cba31f70022a5219d5665fbcb221e99e58bc70122 + languageName: node + linkType: hard + +"npm-normalize-package-bin@npm:^3.0.0": + version: 3.0.1 + resolution: "npm-normalize-package-bin@npm:3.0.1" + checksum: de416d720ab22137a36292ff8a333af499ea0933ef2320a8c6f56a73b0f0448227fec4db5c890d702e26d21d04f271415eab6580b5546456861cc0c19498a4bf + languageName: node + linkType: hard + +"npm-package-arg@npm:8.1.1": + version: 8.1.1 + resolution: "npm-package-arg@npm:8.1.1" + dependencies: + hosted-git-info: ^3.0.6 + semver: ^7.0.0 + validate-npm-package-name: ^3.0.0 + checksum: 406c59f92d8fac5acbd1df62f4af8075e925af51131b6bc66245641ea71ddb0e60b3e2c56fafebd4e8ffc3ba0453e700a221a36a44740dc9f7488cec97ae4c55 + languageName: node + linkType: hard + +"npm-package-arg@npm:^10.0.0, npm-package-arg@npm:^10.1.0": + version: 10.1.0 + resolution: "npm-package-arg@npm:10.1.0" + dependencies: + hosted-git-info: ^6.0.0 + proc-log: ^3.0.0 + semver: ^7.3.5 + validate-npm-package-name: ^5.0.0 + checksum: 8fe4b6a742502345e4836ed42fdf26c544c9f75563c476c67044a481ada6e81f71b55462489c7e1899d516e4347150e58028036a90fa11d47e320bcc9365fd30 + languageName: node + linkType: hard + +"npm-packlist@npm:5.1.1": + version: 5.1.1 + resolution: "npm-packlist@npm:5.1.1" + dependencies: + glob: ^8.0.1 + ignore-walk: ^5.0.1 + npm-bundled: ^1.1.2 + npm-normalize-package-bin: ^1.0.1 + bin: + npm-packlist: bin/index.js + checksum: 28dab153744ceb4695b82a9032d14aa2bfb855d38344a09052673d07860a4d8725f808ed23996e6f2792c48e11f5d147632c159f798d2c24dac92b51a884f0c6 + languageName: node + linkType: hard + +"npm-packlist@npm:^7.0.0": + version: 7.0.4 + resolution: "npm-packlist@npm:7.0.4" + dependencies: + ignore-walk: ^6.0.0 + checksum: 5ffa1f8f0b32141a60a66713fa3ed03b8ee4800b1ed6b59194d03c3c85da88f3fc21e1de29b665f322678bae85198732b16aa76c0a7cb0e283f9e0db50752233 + languageName: node + linkType: hard + +"npm-pick-manifest@npm:^8.0.0": + version: 8.0.1 + resolution: "npm-pick-manifest@npm:8.0.1" + dependencies: + npm-install-checks: ^6.0.0 + npm-normalize-package-bin: ^3.0.0 + npm-package-arg: ^10.0.0 + semver: ^7.3.5 + checksum: b8e16f2fbcc40ba7d1405c9b566bcee32488c6709f883207f709b0715ed34e2f3f3bc5bf5cb9563d6aa23cb878102bf0011ba22cce9235caa9a0349784b48ecd + languageName: node + linkType: hard + +"npm-registry-fetch@npm:^14.0.0, npm-registry-fetch@npm:^14.0.3, npm-registry-fetch@npm:^14.0.5": + version: 14.0.5 + resolution: "npm-registry-fetch@npm:14.0.5" + dependencies: + make-fetch-happen: ^11.0.0 + minipass: ^5.0.0 + minipass-fetch: ^3.0.0 + minipass-json-stream: ^1.0.1 + minizlib: ^2.1.2 + npm-package-arg: ^10.0.0 + proc-log: ^3.0.0 + checksum: c63649642955b424bc1baaff5955027144af312ae117ba8c24829e74484f859482591fe89687c6597d83e930c8054463eef23020ac69146097a72cc62ff10986 + languageName: node + linkType: hard + +"npm-run-path@npm:^4.0.1": + version: 4.0.1 + resolution: "npm-run-path@npm:4.0.1" + dependencies: + path-key: ^3.0.0 + checksum: 5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 + languageName: node + linkType: hard + +"npm-run-path@npm:^5.1.0": + version: 5.1.0 + resolution: "npm-run-path@npm:5.1.0" + dependencies: + path-key: ^4.0.0 + checksum: dc184eb5ec239d6a2b990b43236845332ef12f4e0beaa9701de724aa797fe40b6bbd0157fb7639d24d3ab13f5d5cf22d223a19c6300846b8126f335f788bee66 + languageName: node + linkType: hard + +"npmlog@npm:^5.0.1": + version: 5.0.1 + resolution: "npmlog@npm:5.0.1" + dependencies: + are-we-there-yet: ^2.0.0 + console-control-strings: ^1.1.0 + gauge: ^3.0.0 + set-blocking: ^2.0.0 + checksum: 516b2663028761f062d13e8beb3f00069c5664925871a9b57989642ebe09f23ab02145bf3ab88da7866c4e112cafff72401f61a672c7c8a20edc585a7016ef5f + languageName: node + linkType: hard + +"npmlog@npm:^6.0.0, npmlog@npm:^6.0.2": + version: 6.0.2 + resolution: "npmlog@npm:6.0.2" + dependencies: + are-we-there-yet: ^3.0.0 + console-control-strings: ^1.1.0 + gauge: ^4.0.3 + set-blocking: ^2.0.0 + checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a + languageName: node + linkType: hard + +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: ^1.0.0 + checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 + languageName: node + linkType: hard + +"null-loader@npm:^4.0.0": + version: 4.0.1 + resolution: "null-loader@npm:4.0.1" + dependencies: + loader-utils: ^2.0.0 + schema-utils: ^3.0.0 + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: eeb4c4dd2f8f41e46f5665e4500359109e95ec1028a178a60e0161984906572da7dd87644bcc3cb29f0125d77e2b2508fb4f3813cfb1c6604a15865beb4b987b + languageName: node + linkType: hard + +"nwsapi@npm:^2.2.2": + version: 2.2.2 + resolution: "nwsapi@npm:2.2.2" + checksum: 43769106292bc95f776756ca2f3513dab7b4d506a97c67baec32406447841a35f65f29c1f95ab5d42785210fd41668beed33ca16fa058780be43b101ad73e205 + languageName: node + linkType: hard + +"nx@npm:16.5.2, nx@npm:>=16.5.1 < 17": + version: 16.5.2 + resolution: "nx@npm:16.5.2" + dependencies: + "@nrwl/tao": 16.5.2 + "@nx/nx-darwin-arm64": 16.5.2 + "@nx/nx-darwin-x64": 16.5.2 + "@nx/nx-freebsd-x64": 16.5.2 + "@nx/nx-linux-arm-gnueabihf": 16.5.2 + "@nx/nx-linux-arm64-gnu": 16.5.2 + "@nx/nx-linux-arm64-musl": 16.5.2 + "@nx/nx-linux-x64-gnu": 16.5.2 + "@nx/nx-linux-x64-musl": 16.5.2 + "@nx/nx-win32-arm64-msvc": 16.5.2 + "@nx/nx-win32-x64-msvc": 16.5.2 + "@parcel/watcher": 2.0.4 + "@yarnpkg/lockfile": ^1.1.0 + "@yarnpkg/parsers": 3.0.0-rc.46 + "@zkochan/js-yaml": 0.0.6 + axios: ^1.0.0 + chalk: ^4.1.0 + cli-cursor: 3.1.0 + cli-spinners: 2.6.1 + cliui: ^7.0.2 + dotenv: ~10.0.0 + enquirer: ~2.3.6 + fast-glob: 3.2.7 + figures: 3.2.0 + flat: ^5.0.2 + fs-extra: ^11.1.0 + glob: 7.1.4 + ignore: ^5.0.4 + js-yaml: 4.1.0 + jsonc-parser: 3.2.0 + lines-and-columns: ~2.0.3 + minimatch: 3.0.5 + npm-run-path: ^4.0.1 + open: ^8.4.0 + semver: 7.5.3 + string-width: ^4.2.3 + strong-log-transformer: ^2.1.0 + tar-stream: ~2.2.0 + tmp: ~0.2.1 + tsconfig-paths: ^4.1.2 + tslib: ^2.3.0 + v8-compile-cache: 2.3.0 + yargs: ^17.6.2 + yargs-parser: 21.1.1 + peerDependencies: + "@swc-node/register": ^1.4.2 + "@swc/core": ^1.2.173 + dependenciesMeta: + "@nx/nx-darwin-arm64": + optional: true + "@nx/nx-darwin-x64": + optional: true + "@nx/nx-freebsd-x64": + optional: true + "@nx/nx-linux-arm-gnueabihf": + optional: true + "@nx/nx-linux-arm64-gnu": + optional: true + "@nx/nx-linux-arm64-musl": + optional: true + "@nx/nx-linux-x64-gnu": + optional: true + "@nx/nx-linux-x64-musl": + optional: true + "@nx/nx-win32-arm64-msvc": + optional: true + "@nx/nx-win32-x64-msvc": + optional: true + peerDependenciesMeta: + "@swc-node/register": + optional: true + "@swc/core": + optional: true + bin: + nx: bin/nx.js + checksum: 717da8be398dd1d6a19419dc579cb4197c76de49577edf664ce8a9fdb341176823a277988d4b2b625ec7812ef498a6d4dfecf987d9cc0b981628cd235b09b8f0 + languageName: node + linkType: hard + +"oauth-sign@npm:~0.9.0": + version: 0.9.0 + resolution: "oauth-sign@npm:0.9.0" + checksum: 8f5497a127967866a3c67094c21efd295e46013a94e6e828573c62220e9af568cc1d2d04b16865ba583e430510fa168baf821ea78f355146d8ed7e350fc44c64 + languageName: node + linkType: hard + +"object-assign@npm:^4, object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f + languageName: node + linkType: hard + +"object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0": + version: 1.12.3 + resolution: "object-inspect@npm:1.12.3" + checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db + languageName: node + linkType: hard + +"object-keys@npm:^1.1.1": + version: 1.1.1 + resolution: "object-keys@npm:1.1.1" + checksum: b363c5e7644b1e1b04aa507e88dcb8e3a2f52b6ffd0ea801e4c7a62d5aa559affe21c55a07fd4b1fd55fc03a33c610d73426664b20032405d7b92a1414c34d6a + languageName: node + linkType: hard + +"object.assign@npm:^4.1.0, object.assign@npm:^4.1.3, object.assign@npm:^4.1.4": + version: 4.1.4 + resolution: "object.assign@npm:4.1.4" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + has-symbols: ^1.0.3 + object-keys: ^1.1.1 + checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 + languageName: node + linkType: hard + +"object.entries@npm:^1.1.6": + version: 1.1.6 + resolution: "object.entries@npm:1.1.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 0f8c47517e6a9a980241eafe3b73de11e59511883173c2b93d67424a008e47e11b77c80e431ad1d8a806f6108b225a1cab9223e53e555776c612a24297117d28 + languageName: node + linkType: hard + +"object.fromentries@npm:^2.0.6": + version: 2.0.6 + resolution: "object.fromentries@npm:2.0.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 453c6d694180c0c30df451b60eaf27a5b9bca3fb43c37908fd2b78af895803dc631242bcf05582173afa40d8d0e9c96e16e8874b39471aa53f3ac1f98a085d85 + languageName: node + linkType: hard + +"object.hasown@npm:^1.1.2": + version: 1.1.2 + resolution: "object.hasown@npm:1.1.2" + dependencies: + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: b936572536db0cdf38eb30afd2f1026a8b6f2cc5d2c4497c9d9bbb01eaf3e980dead4fd07580cfdd098e6383e5a9db8212d3ea0c6bdd2b5e68c60aa7e3b45566 + languageName: node + linkType: hard + +"object.values@npm:^1.1.6": + version: 1.1.6 + resolution: "object.values@npm:1.1.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: f6fff9fd817c24cfd8107f50fb33061d81cd11bacc4e3dbb3852e9ff7692fde4dbce823d4333ea27cd9637ef1b6690df5fbb61f1ed314fa2959598dc3ae23d8e + languageName: node + linkType: hard + +"on-exit-leak-free@npm:^0.2.0": + version: 0.2.0 + resolution: "on-exit-leak-free@npm:0.2.0" + checksum: d22b0f0538069110626b578db6e68b6ee0e85b1ee9cc5ef9b4de1bba431431d6a8da91a61e09d2ad46f22a96f968e5237833cb9d0b69bc4d294f7ec82f609b05 + languageName: node + linkType: hard + +"on-finished@npm:2.4.1": + version: 2.4.1 + resolution: "on-finished@npm:2.4.1" + dependencies: + ee-first: 1.1.1 + checksum: d20929a25e7f0bb62f937a425b5edeb4e4cde0540d77ba146ec9357f00b0d497cdb3b9b05b9c8e46222407d1548d08166bff69cc56dfa55ba0e4469228920ff0 + languageName: node + linkType: hard + +"on-headers@npm:~1.0.2": + version: 1.0.2 + resolution: "on-headers@npm:1.0.2" + checksum: 2bf13467215d1e540a62a75021e8b318a6cfc5d4fc53af8e8f84ad98dbcea02d506c6d24180cd62e1d769c44721ba542f3154effc1f7579a8288c9f7873ed8e5 + languageName: node + linkType: hard + +"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: 1 + checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 + languageName: node + linkType: hard + +"once@npm:~1.3.0": + version: 1.3.3 + resolution: "once@npm:1.3.3" + dependencies: + wrappy: 1 + checksum: 8e832de08b1d73b470e01690c211cb4fcefccab1fd1bd19e706d572d74d3e9b7e38a8bfcdabdd364f9f868757d9e8e5812a59817dc473eaf698ff3bfae2219f2 + languageName: node + linkType: hard + +"onetime@npm:^5.1.0, onetime@npm:^5.1.2": + version: 5.1.2 + resolution: "onetime@npm:5.1.2" + dependencies: + mimic-fn: ^2.1.0 + checksum: 2478859ef817fc5d4e9c2f9e5728512ddd1dbc9fb7829ad263765bb6d3b91ce699d6e2332eef6b7dff183c2f490bd3349f1666427eaba4469fba0ac38dfd0d34 + languageName: node + linkType: hard + +"onetime@npm:^6.0.0": + version: 6.0.0 + resolution: "onetime@npm:6.0.0" + dependencies: + mimic-fn: ^4.0.0 + checksum: 0846ce78e440841335d4e9182ef69d5762e9f38aa7499b19f42ea1c4cd40f0b4446094c455c713f9adac3f4ae86f613bb5e30c99e52652764d06a89f709b3788 + languageName: node + linkType: hard + +"ono@npm:^4.0.11": + version: 4.0.11 + resolution: "ono@npm:4.0.11" + dependencies: + format-util: ^1.0.3 + checksum: fabfdddb2e5e9875098e628871c86daf2fe0d1cbbfcdcc33093f47911eb4c386444410bc2bd3f6af9ff484deed46c6f9d88c8d49107ddec5350a9b089b283dd6 + languageName: node + linkType: hard + +"open@npm:^8.4.0": + version: 8.4.2 + resolution: "open@npm:8.4.2" + dependencies: + define-lazy-prop: ^2.0.0 + is-docker: ^2.1.1 + is-wsl: ^2.2.0 + checksum: 6388bfff21b40cb9bd8f913f9130d107f2ed4724ea81a8fd29798ee322b361ca31fa2cdfb491a5c31e43a3996cfe9566741238c7a741ada8d7af1cb78d85cf26 + languageName: node + linkType: hard + +"open@npm:^9.1.0": + version: 9.1.0 + resolution: "open@npm:9.1.0" + dependencies: + default-browser: ^4.0.0 + define-lazy-prop: ^3.0.0 + is-inside-container: ^1.0.0 + is-wsl: ^2.2.0 + checksum: 3993c0f61d51fed8ac290e99c9c3cf45d3b6cfb3e2aa2b74cafd312c3486c22fd81df16ac8f3ab91dd8a4e3e729a16fc2480cfc406c4833416cf908acf1ae7c9 + languageName: node + linkType: hard + +"opener@npm:^1.5.2": + version: 1.5.2 + resolution: "opener@npm:1.5.2" + bin: + opener: bin/opener-bin.js + checksum: 33b620c0d53d5b883f2abc6687dd1c5fd394d270dbe33a6356f2d71e0a2ec85b100d5bac94694198ccf5c30d592da863b2292c5539009c715a9c80c697b4f6cc + languageName: node + linkType: hard + +"optionator@npm:^0.8.1": + version: 0.8.3 + resolution: "optionator@npm:0.8.3" + 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 + checksum: b8695ddf3d593203e25ab0900e265d860038486c943ff8b774f596a310f8ceebdb30c6832407a8198ba3ec9debe1abe1f51d4aad94843612db3b76d690c61d34 + languageName: node + linkType: hard + +"optionator@npm:^0.9.1": + version: 0.9.1 + resolution: "optionator@npm:0.9.1" + dependencies: + deep-is: ^0.1.3 + fast-levenshtein: ^2.0.6 + levn: ^0.4.1 + prelude-ls: ^1.2.1 + type-check: ^0.4.0 + word-wrap: ^1.2.3 + checksum: dbc6fa065604b24ea57d734261914e697bd73b69eff7f18e967e8912aa2a40a19a9f599a507fa805be6c13c24c4eae8c71306c239d517d42d4c041c942f508a0 + languageName: node + linkType: hard + +"ora@npm:^5.4.1": + version: 5.4.1 + resolution: "ora@npm:5.4.1" + dependencies: + bl: ^4.1.0 + chalk: ^4.1.0 + cli-cursor: ^3.1.0 + cli-spinners: ^2.5.0 + is-interactive: ^1.0.0 + is-unicode-supported: ^0.1.0 + log-symbols: ^4.1.0 + strip-ansi: ^6.0.0 + wcwidth: ^1.0.1 + checksum: 28d476ee6c1049d68368c0dc922e7225e3b5600c3ede88fade8052837f9ed342625fdaa84a6209302587c8ddd9b664f71f0759833cbdb3a4cf81344057e63c63 + languageName: node + linkType: hard + +"ora@npm:^6.1.2": + version: 6.1.2 + resolution: "ora@npm:6.1.2" + dependencies: + bl: ^5.0.0 + chalk: ^5.0.0 + cli-cursor: ^4.0.0 + cli-spinners: ^2.6.1 + is-interactive: ^2.0.0 + is-unicode-supported: ^1.1.0 + log-symbols: ^5.1.0 + strip-ansi: ^7.0.1 + wcwidth: ^1.0.1 + checksum: d5af3d67ad7affcf3029ffe3ef547f3335fb72abdc382040ae8bd75ad5c629f5d165ed9e398fd4fb08100701eafbec34bb9dc3f29e919f6f75c443290faa1db2 + languageName: node + linkType: hard + +"os-tmpdir@npm:~1.0.2": + version: 1.0.2 + resolution: "os-tmpdir@npm:1.0.2" + checksum: 5666560f7b9f10182548bf7013883265be33620b1c1b4a4d405c25be2636f970c5488ff3e6c48de75b55d02bde037249fe5dbfbb4c0fb7714953d56aed062e6d + languageName: node + linkType: hard + +"os@npm:~0.1.1": + version: 0.1.2 + resolution: "os@npm:0.1.2" + checksum: dc2d99759eef13f5dc47ddb12c67b9760a7196fd83a35a7aec2d75b82f91163ca1d4e8872238f8c2a35f4cddd5adf5ce6638a234c0563c748d3cd1d69a9f7153 + languageName: node + linkType: hard + +"p-cancelable@npm:^2.0.0": + version: 2.1.1 + resolution: "p-cancelable@npm:2.1.1" + checksum: 3dba12b4fb4a1e3e34524535c7858fc82381bbbd0f247cc32dedc4018592a3950ce66b106d0880b4ec4c2d8d6576f98ca885dc1d7d0f274d1370be20e9523ddf + languageName: node + linkType: hard + +"p-finally@npm:^1.0.0": + version: 1.0.0 + resolution: "p-finally@npm:1.0.0" + checksum: 93a654c53dc805dd5b5891bab16eb0ea46db8f66c4bfd99336ae929323b1af2b70a8b0654f8f1eae924b2b73d037031366d645f1fd18b3d30cbd15950cc4b1d4 + languageName: node + linkType: hard + +"p-limit@npm:^1.1.0": + version: 1.3.0 + resolution: "p-limit@npm:1.3.0" + dependencies: + p-try: ^1.0.0 + checksum: 281c1c0b8c82e1ac9f81acd72a2e35d402bf572e09721ce5520164e9de07d8274451378a3470707179ad13240535558f4b277f02405ad752e08c7d5b0d54fbfd + languageName: node + linkType: hard + +"p-limit@npm:^2.2.0": + version: 2.3.0 + resolution: "p-limit@npm:2.3.0" + dependencies: + p-try: ^2.0.0 + checksum: 84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 + languageName: node + linkType: hard + +"p-limit@npm:^3.0.2, p-limit@npm:^3.1.0": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" + dependencies: + yocto-queue: ^0.1.0 + checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 + languageName: node + linkType: hard + +"p-locate@npm:^2.0.0": + version: 2.0.0 + resolution: "p-locate@npm:2.0.0" + dependencies: + p-limit: ^1.1.0 + checksum: e2dceb9b49b96d5513d90f715780f6f4972f46987dc32a0e18bc6c3fc74a1a5d73ec5f81b1398af5e58b99ea1ad03fd41e9181c01fa81b4af2833958696e3081 + languageName: node + linkType: hard + +"p-locate@npm:^4.1.0": + version: 4.1.0 + resolution: "p-locate@npm:4.1.0" + dependencies: + p-limit: ^2.2.0 + checksum: 513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 + languageName: node + linkType: hard + +"p-locate@npm:^5.0.0": + version: 5.0.0 + resolution: "p-locate@npm:5.0.0" + dependencies: + p-limit: ^3.0.2 + checksum: 1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 + languageName: node + linkType: hard + +"p-map-series@npm:2.1.0": + version: 2.1.0 + resolution: "p-map-series@npm:2.1.0" + checksum: 69d4efbb6951c0dd62591d5a18c3af0af78496eae8b55791e049da239d70011aa3af727dece3fc9943e0bb3fd4fa64d24177cfbecc46efaf193179f0feeac486 + languageName: node + linkType: hard + +"p-map@npm:4.0.0, p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: ^3.0.0 + checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c + languageName: node + linkType: hard + +"p-pipe@npm:3.1.0": + version: 3.1.0 + resolution: "p-pipe@npm:3.1.0" + checksum: ee9a2609685f742c6ceb3122281ec4453bbbcc80179b13e66fd139dcf19b1c327cf6c2fdfc815b548d6667e7eaefe5396323f6d49c4f7933e4cef47939e3d65c + languageName: node + linkType: hard + +"p-queue@npm:6.6.2": + version: 6.6.2 + resolution: "p-queue@npm:6.6.2" + dependencies: + eventemitter3: ^4.0.4 + p-timeout: ^3.2.0 + checksum: 832642fcc4ab6477b43e6d7c30209ab10952969ed211c6d6f2931be8a4f9935e3578c72e8cce053dc34f2eb6941a408a2c516a54904e989851a1a209cf19761c + languageName: node + linkType: hard + +"p-reduce@npm:2.1.0, p-reduce@npm:^2.0.0, p-reduce@npm:^2.1.0": + version: 2.1.0 + resolution: "p-reduce@npm:2.1.0" + checksum: 99b26d36066a921982f25c575e78355824da0787c486e3dd9fc867460e8bf17d5fb3ce98d006b41bdc81ffc0aa99edf5faee53d11fe282a20291fb721b0cb1c7 + languageName: node + linkType: hard + +"p-timeout@npm:^3.2.0": + version: 3.2.0 + resolution: "p-timeout@npm:3.2.0" + dependencies: + p-finally: ^1.0.0 + checksum: 3dd0eaa048780a6f23e5855df3dd45c7beacff1f820476c1d0d1bcd6648e3298752ba2c877aa1c92f6453c7dd23faaf13d9f5149fc14c0598a142e2c5e8d649c + languageName: node + linkType: hard + +"p-try@npm:^1.0.0": + version: 1.0.0 + resolution: "p-try@npm:1.0.0" + checksum: 3b5303f77eb7722144154288bfd96f799f8ff3e2b2b39330efe38db5dd359e4fb27012464cd85cb0a76e9b7edd1b443568cb3192c22e7cffc34989df0bafd605 + languageName: node + linkType: hard + +"p-try@npm:^2.0.0": + version: 2.2.0 + resolution: "p-try@npm:2.2.0" + checksum: f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae + languageName: node + linkType: hard + +"p-waterfall@npm:2.1.1": + version: 2.1.1 + resolution: "p-waterfall@npm:2.1.1" + dependencies: + p-reduce: ^2.0.0 + checksum: 8588bb8b004ee37e559c7e940a480c1742c42725d477b0776ff30b894920a3e48bddf8f60aa0ae82773e500a8fc99d75e947c450e0c2ce187aff72cc1b248f6d + languageName: node + linkType: hard + +"package-json@npm:^7.0.0": + version: 7.0.0 + resolution: "package-json@npm:7.0.0" + dependencies: + got: ^11.8.2 + registry-auth-token: ^4.0.0 + registry-url: ^5.0.0 + semver: ^7.3.5 + checksum: c03699b057f665c5bf2d6af76190b8fb32aaf69c70a78faf7c073c03c3d0d5e168d4a96f386739a4d179e925e66289bf0b93a446fbb3f97b05451a3cd2a3bd90 + languageName: node + linkType: hard + +"pacote@npm:^15.2.0": + version: 15.2.0 + resolution: "pacote@npm:15.2.0" + dependencies: + "@npmcli/git": ^4.0.0 + "@npmcli/installed-package-contents": ^2.0.1 + "@npmcli/promise-spawn": ^6.0.1 + "@npmcli/run-script": ^6.0.0 + cacache: ^17.0.0 + fs-minipass: ^3.0.0 + minipass: ^5.0.0 + npm-package-arg: ^10.0.0 + npm-packlist: ^7.0.0 + npm-pick-manifest: ^8.0.0 + npm-registry-fetch: ^14.0.0 + proc-log: ^3.0.0 + promise-retry: ^2.0.1 + read-package-json: ^6.0.0 + read-package-json-fast: ^3.0.0 + sigstore: ^1.3.0 + ssri: ^10.0.0 + tar: ^6.1.11 + bin: + pacote: lib/bin.js + checksum: c731572be2bf226b117eba076d242bd4cd8be7aa01e004af3374a304ad7ab330539e22644bc33de12d2a7d45228ccbcbf4d710f59c84414f3d09a1a95ee6f0bf + languageName: node + linkType: hard + +"param-case@npm:^3.0.3, param-case@npm:^3.0.4": + version: 3.0.4 + resolution: "param-case@npm:3.0.4" + dependencies: + dot-case: ^3.0.4 + tslib: ^2.0.3 + checksum: b34227fd0f794e078776eb3aa6247442056cb47761e9cd2c4c881c86d84c64205f6a56ef0d70b41ee7d77da02c3f4ed2f88e3896a8fefe08bdfb4deca037c687 + languageName: node + linkType: hard + +"parent-module@npm:^1.0.0": + version: 1.0.1 + resolution: "parent-module@npm:1.0.1" + dependencies: + callsites: ^3.0.0 + checksum: 6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff + languageName: node + linkType: hard + +"parse-json@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-json@npm:4.0.0" + dependencies: + error-ex: ^1.3.1 + json-parse-better-errors: ^1.0.1 + checksum: 0fe227d410a61090c247e34fa210552b834613c006c2c64d9a05cfe9e89cf8b4246d1246b1a99524b53b313e9ac024438d0680f67e33eaed7e6f38db64cfe7b5 + languageName: node + linkType: hard + +"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" + 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 + checksum: 62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 + languageName: node + linkType: hard + +"parse-path@npm:^7.0.0": + version: 7.0.0 + resolution: "parse-path@npm:7.0.0" + dependencies: + protocols: ^2.0.0 + checksum: 244b46523a58181d251dda9b888efde35d8afb957436598d948852f416d8c76ddb4f2010f9fc94218b4be3e5c0f716aa0d2026194a781e3b8981924142009302 + languageName: node + linkType: hard + +"parse-srcset@npm:^1.0.2": + version: 1.0.2 + resolution: "parse-srcset@npm:1.0.2" + checksum: 3a0380380c6082021fcce982f0b89fb8a493ce9dfd7d308e5e6d855201e80db8b90438649b31fdd82a3d6089a8ca17dccddaa2b730a718389af4c037b8539ebf + languageName: node + linkType: hard + +"parse-url@npm:^8.1.0": + version: 8.1.0 + resolution: "parse-url@npm:8.1.0" + dependencies: + parse-path: ^7.0.0 + checksum: b93e21ab4c93c7d7317df23507b41be7697694d4c94f49ed5c8d6288b01cba328fcef5ba388e147948eac20453dee0df9a67ab2012415189fff85973bdffe8d9 + languageName: node + linkType: hard + +"parse5@npm:^7.0.0, parse5@npm:^7.1.1": + version: 7.1.2 + resolution: "parse5@npm:7.1.2" + dependencies: + entities: ^4.4.0 + checksum: 59465dd05eb4c5ec87b76173d1c596e152a10e290b7abcda1aecf0f33be49646ea74840c69af975d7887543ea45564801736356c568d6b5e71792fd0f4055713 + languageName: node + linkType: hard + +"parseurl@npm:~1.3.3": + version: 1.3.3 + resolution: "parseurl@npm:1.3.3" + checksum: 407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 + languageName: node + linkType: hard + +"pascal-case@npm:^3.1.2": + version: 3.1.2 + resolution: "pascal-case@npm:3.1.2" + dependencies: + no-case: ^3.0.4 + tslib: ^2.0.3 + checksum: ba98bfd595fc91ef3d30f4243b1aee2f6ec41c53b4546bfa3039487c367abaa182471dcfc830a1f9e1a0df00c14a370514fa2b3a1aacc68b15a460c31116873e + languageName: node + linkType: hard + +"path-browserify@npm:^1.0.0": + version: 1.0.1 + resolution: "path-browserify@npm:1.0.1" + checksum: c6d7fa376423fe35b95b2d67990060c3ee304fc815ff0a2dc1c6c3cfaff2bd0d572ee67e18f19d0ea3bbe32e8add2a05021132ac40509416459fffee35200699 + languageName: node + linkType: hard + +"path-exists@npm:^3.0.0": + version: 3.0.0 + resolution: "path-exists@npm:3.0.0" + checksum: 96e92643aa34b4b28d0de1cd2eba52a1c5313a90c6542d03f62750d82480e20bfa62bc865d5cfc6165f5fcd5aeb0851043c40a39be5989646f223300021bae0a + languageName: node + linkType: hard + +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 + languageName: node + linkType: hard + +"path-is-absolute@npm:^1.0.0": + version: 1.0.1 + resolution: "path-is-absolute@npm:1.0.1" + checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + languageName: node + linkType: hard + +"path-key@npm:^3.0.0, path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 + languageName: node + linkType: hard + +"path-key@npm:^4.0.0": + version: 4.0.0 + resolution: "path-key@npm:4.0.0" + checksum: 8e6c314ae6d16b83e93032c61020129f6f4484590a777eed709c4a01b50e498822b00f76ceaf94bc64dbd90b327df56ceadce27da3d83393790f1219e07721d7 + languageName: node + linkType: hard + +"path-parse@npm:^1.0.7": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a + languageName: node + linkType: hard + +"path-scurry@npm:^1.6.1, path-scurry@npm:^1.7.0": + version: 1.9.2 + resolution: "path-scurry@npm:1.9.2" + dependencies: + lru-cache: ^9.1.1 + minipass: ^5.0.0 || ^6.0.2 + checksum: 92888dfb68e285043c6d3291c8e971d5d2bc2f5082f4d7b5392896f34be47024c9d0a8b688dd7ae6d125acc424699195474927cb4f00049a9b1ec7c4256fa8e0 + languageName: node + linkType: hard + +"path-to-regexp@npm:0.1.7": + version: 0.1.7 + resolution: "path-to-regexp@npm:0.1.7" + checksum: 69a14ea24db543e8b0f4353305c5eac6907917031340e5a8b37df688e52accd09e3cebfe1660b70d76b6bd89152f52183f28c74813dbf454ba1a01c82a38abce + languageName: node + linkType: hard + +"path-type@npm:^3.0.0": + version: 3.0.0 + resolution: "path-type@npm:3.0.0" + dependencies: + pify: ^3.0.0 + checksum: 735b35e256bad181f38fa021033b1c33cfbe62ead42bb2222b56c210e42938eecb272ae1949f3b6db4ac39597a61b44edd8384623ec4d79bfdc9a9c0f12537a6 + languageName: node + linkType: hard + +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 + languageName: node + linkType: hard + +"path@npm:~0.12.7": + version: 0.12.7 + resolution: "path@npm:0.12.7" + dependencies: + process: ^0.11.1 + util: ^0.10.3 + checksum: 5dedb71e78fc008fcba797defc0b4e1cf06c1f18e0a631e03ba5bb505136f587ff017afc14f9a3d481cbe77aeedff7dc0c1d2ce4d820c1ebf3c4281ca49423a1 + languageName: node + linkType: hard + +"performance-now@npm:^2.1.0": + version: 2.1.0 + resolution: "performance-now@npm:2.1.0" + checksum: 534e641aa8f7cba160f0afec0599b6cecefbb516a2e837b512be0adbe6c1da5550e89c78059c7fabc5c9ffdf6627edabe23eb7c518c4500067a898fa65c2b550 + languageName: node + linkType: hard + +"picocolors@npm:^1.0.0": + version: 1.0.0 + resolution: "picocolors@npm:1.0.0" + checksum: a2e8092dd86c8396bdba9f2b5481032848525b3dc295ce9b57896f931e63fc16f79805144321f72976383fc249584672a75cc18d6777c6b757603f372f745981 + languageName: node + linkType: hard + +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf + languageName: node + linkType: hard + +"pify@npm:5.0.0": + version: 5.0.0 + resolution: "pify@npm:5.0.0" + checksum: 443e3e198ad6bfa8c0c533764cf75c9d5bc976387a163792fb553ffe6ce923887cf14eebf5aea9b7caa8eab930da8c33612990ae85bd8c2bc18bedb9eae94ecb + languageName: node + linkType: hard + +"pify@npm:^2.3.0": + version: 2.3.0 + resolution: "pify@npm:2.3.0" + checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba + languageName: node + linkType: hard + +"pify@npm:^3.0.0": + version: 3.0.0 + resolution: "pify@npm:3.0.0" + checksum: 6cdcbc3567d5c412450c53261a3f10991665d660961e06605decf4544a61a97a54fefe70a68d5c37080ff9d6f4cf51444c90198d1ba9f9309a6c0d6e9f5c4fde + languageName: node + linkType: hard + +"pify@npm:^4.0.1": + version: 4.0.1 + resolution: "pify@npm:4.0.1" + checksum: 9c4e34278cb09987685fa5ef81499c82546c033713518f6441778fbec623fc708777fe8ac633097c72d88470d5963094076c7305cafc7ad340aae27cfacd856b + languageName: node + linkType: hard + +"pino-abstract-transport@npm:1.0.0": + version: 1.0.0 + resolution: "pino-abstract-transport@npm:1.0.0" + dependencies: + readable-stream: ^4.0.0 + split2: ^4.0.0 + checksum: 05dd0eda52dd99fd204b39fe7b62656744b63e863bc052cdd5105d25f226a236966d0a46e39a1ace4838f6e988c608837ff946d2d0bc92835ca7baa0a3bff8d8 + languageName: node + linkType: hard + +"pino-abstract-transport@npm:v0.5.0": + version: 0.5.0 + resolution: "pino-abstract-transport@npm:0.5.0" + dependencies: + duplexify: ^4.1.2 + split2: ^4.0.0 + checksum: c503f867de3189f8217ab9cf794e8a631dddd0029a829f0f985f5511308152ebd53e363764fbc5570b3d1c715b341e3923456ce16ad84cd41be2b9a074ada234 + languageName: node + linkType: hard + +"pino-std-serializers@npm:^4.0.0": + version: 4.0.0 + resolution: "pino-std-serializers@npm:4.0.0" + checksum: 89d487729b58c9d3273a0ee851ead068d6d2e2ccc1af8e1c1d28f1b3442423679bec7ec04d9a2aba36f94f335e82be9f4de19dc4fbc161e71c136aaa15b85ad3 + languageName: node + linkType: hard + +"pino@npm:7.11.0": + version: 7.11.0 + resolution: "pino@npm:7.11.0" + dependencies: + atomic-sleep: ^1.0.0 + fast-redact: ^3.0.0 + on-exit-leak-free: ^0.2.0 + pino-abstract-transport: v0.5.0 + pino-std-serializers: ^4.0.0 + process-warning: ^1.0.0 + quick-format-unescaped: ^4.0.3 + real-require: ^0.1.0 + safe-stable-stringify: ^2.1.0 + sonic-boom: ^2.2.1 + thread-stream: ^0.15.1 + bin: + pino: bin.js + checksum: b919e7dbe41de978bb050dcef94fd687c012eb78d344a18f75f04ce180d5810fc162be1f136722d70cd005ed05832c4023a38b9acbc1076ae63c9f5ec5ca515c + languageName: node + linkType: hard + +"pirates@npm:^4.0.4": + version: 4.0.5 + resolution: "pirates@npm:4.0.5" + checksum: c9994e61b85260bec6c4fc0307016340d9b0c4f4b6550a957afaaff0c9b1ad58fbbea5cfcf083860a25cb27a375442e2b0edf52e2e1e40e69934e08dcc52d227 + languageName: node + linkType: hard + +"pkg-dir@npm:^4.2.0": + version: 4.2.0 + resolution: "pkg-dir@npm:4.2.0" + dependencies: + find-up: ^4.0.0 + checksum: 9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 + languageName: node + linkType: hard + +"pkginfo@npm:0.4.1": + version: 0.4.1 + resolution: "pkginfo@npm:0.4.1" + checksum: 0f13694f3682345647b7cb887fb6fe258df51b635f252324cd75eeb8181b4381cb8b9d91dc2d869849e857192b403bea65038d2f7c05b524eeae69ece5048209 + languageName: node + linkType: hard + +"playwright-core@npm:1.32.2": + version: 1.32.2 + resolution: "playwright-core@npm:1.32.2" + bin: + playwright: cli.js + checksum: ff000cbf280e5d558fe70fd3edf14910a2e86ec68b04e28327176268345be7b3f88a5d22d78e8dae677dd633dce6cd493237df199773b55312f2ae1ab85d711f + languageName: node + linkType: hard + +"pluralize@npm:^7.0.0": + version: 7.0.0 + resolution: "pluralize@npm:7.0.0" + checksum: e3f694924b7c8c03dc9fa40b2312e17787998ac6e20fccace11efa1146046eb9931541bfd247b3ec5535e730d902a5aee7c32681d5bf9a00fc74a72039a3e609 + languageName: node + linkType: hard + +"postcss-modules-extract-imports@npm:^3.0.0": + version: 3.0.0 + resolution: "postcss-modules-extract-imports@npm:3.0.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 4b65f2f1382d89c4bc3c0a1bdc5942f52f3cb19c110c57bd591ffab3a5fee03fcf831604168205b0c1b631a3dce2255c70b61aaae3ef39d69cd7eb450c2552d2 + languageName: node + linkType: hard + +"postcss-modules-local-by-default@npm:^4.0.0": + version: 4.0.0 + resolution: "postcss-modules-local-by-default@npm:4.0.0" + dependencies: + icss-utils: ^5.0.0 + postcss-selector-parser: ^6.0.2 + postcss-value-parser: ^4.1.0 + peerDependencies: + postcss: ^8.1.0 + checksum: 6cf570badc7bc26c265e073f3ff9596b69bb954bc6ac9c5c1b8cba2995b80834226b60e0a3cbb87d5f399dbb52e6466bba8aa1d244f6218f99d834aec431a69d + languageName: node + linkType: hard + +"postcss-modules-scope@npm:^3.0.0": + version: 3.0.0 + resolution: "postcss-modules-scope@npm:3.0.0" + dependencies: + postcss-selector-parser: ^6.0.4 + peerDependencies: + postcss: ^8.1.0 + checksum: 330b9398dbd44c992c92b0dc612c0626135e2cc840fee41841eb61247a6cfed95af2bd6f67ead9dd9d0bb41f5b0367129d93c6e434fa3e9c58ade391d9a5a138 + languageName: node + linkType: hard + +"postcss-modules-values@npm:^4.0.0": + version: 4.0.0 + resolution: "postcss-modules-values@npm:4.0.0" + dependencies: + icss-utils: ^5.0.0 + peerDependencies: + postcss: ^8.1.0 + checksum: f7f2cdf14a575b60e919ad5ea52fed48da46fe80db2733318d71d523fc87db66c835814940d7d05b5746b0426e44661c707f09bdb83592c16aea06e859409db6 + languageName: node + linkType: hard + +"postcss-resolve-nested-selector@npm:^0.1.1": + version: 0.1.1 + resolution: "postcss-resolve-nested-selector@npm:0.1.1" + checksum: b08fb76ab092a09ee01328bad620a01dcb445ac5eb02dd0ed9ed75217c2f779ecb3bf99a361c46e695689309c08c09f1a1ad7354c8d58c2c2c40d364657fcb08 + languageName: node + linkType: hard + +"postcss-safe-parser@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-safe-parser@npm:6.0.0" + peerDependencies: + postcss: ^8.3.3 + checksum: 06c733eaad83a3954367e7ee02ddfe3796e7a44d4299ccf9239f40964a4daac153c7d77613f32964b5a86c0c6c2f6167738f31d578b73b17cb69d0c4446f0ebe + languageName: node + linkType: hard + +"postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4": + version: 6.0.13 + resolution: "postcss-selector-parser@npm:6.0.13" + dependencies: + cssesc: ^3.0.0 + util-deprecate: ^1.0.2 + checksum: f89163338a1ce3b8ece8e9055cd5a3165e79a15e1c408e18de5ad8f87796b61ec2d48a2902d179ae0c4b5de10fccd3a325a4e660596549b040bc5ad1b465f096 + languageName: node + linkType: hard + +"postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": + version: 4.2.0 + resolution: "postcss-value-parser@npm:4.2.0" + checksum: 819ffab0c9d51cf0acbabf8996dffbfafbafa57afc0e4c98db88b67f2094cb44488758f06e5da95d7036f19556a4a732525e84289a425f4f6fd8e412a9d7442f + languageName: node + linkType: hard + +"postcss@npm:^8.3.11, postcss@npm:^8.4.19, postcss@npm:^8.4.24": + version: 8.4.31 + resolution: "postcss@npm:8.4.31" + dependencies: + nanoid: ^3.3.6 + picocolors: ^1.0.0 + source-map-js: ^1.0.2 + checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea + languageName: node + linkType: hard + +"prelude-ls@npm:^1.2.1": + version: 1.2.1 + resolution: "prelude-ls@npm:1.2.1" + checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a + languageName: node + linkType: hard + +"prelude-ls@npm:~1.1.2": + version: 1.1.2 + resolution: "prelude-ls@npm:1.1.2" + checksum: c4867c87488e4a0c233e158e4d0d5565b609b105d75e4c05dc760840475f06b731332eb93cc8c9cecb840aa8ec323ca3c9a56ad7820ad2e63f0261dadcb154e4 + languageName: node + linkType: hard + +"prettier-linter-helpers@npm:^1.0.0": + version: 1.0.0 + resolution: "prettier-linter-helpers@npm:1.0.0" + dependencies: + fast-diff: ^1.1.2 + checksum: 00ce8011cf6430158d27f9c92cfea0a7699405633f7f1d4a45f07e21bf78e99895911cbcdc3853db3a824201a7c745bd49bfea8abd5fb9883e765a90f74f8392 + languageName: node + linkType: hard + +"prettier@npm:^1.19.1": + version: 1.19.1 + resolution: "prettier@npm:1.19.1" + bin: + prettier: ./bin-prettier.js + checksum: bc78219e0f8173a808f4c6c8e0a137dd8ebd4fbe013e63fe1a37a82b48612f17b8ae8e18a992adf802ee2cf7428f14f084e7c2846ca5759cf4013c6e54810e1f + languageName: node + linkType: hard + +"prettier@npm:~2.6.0": + version: 2.6.2 + resolution: "prettier@npm:2.6.2" + bin: + prettier: bin-prettier.js + checksum: 48d08dde8e9fb1f5bccdd205baa7f192e9fc8bc98f86e1b97d919de804e28c806b0e6cc685e4a88211aa7987fa9668f30baae19580d87ced3ed0f2ec6572106f + languageName: node + linkType: hard + +"prettier@npm:~3.0.0": + version: 3.0.0 + resolution: "prettier@npm:3.0.0" + bin: + prettier: bin/prettier.cjs + checksum: 6a832876a1552dc58330d2467874e5a0b46b9ccbfc5d3531eb69d15684743e7f83dc9fbd202db6270446deba9c82b79d24383d09924c462b457136a759425e33 + languageName: node + linkType: hard + +"pretty-bytes@npm:^5.1.0": + version: 5.6.0 + resolution: "pretty-bytes@npm:5.6.0" + checksum: 9c082500d1e93434b5b291bd651662936b8bd6204ec9fa17d563116a192d6d86b98f6d328526b4e8d783c07d5499e2614a807520249692da9ec81564b2f439cd + languageName: node + linkType: hard + +"pretty-error@npm:^4.0.0": + version: 4.0.0 + resolution: "pretty-error@npm:4.0.0" + dependencies: + lodash: ^4.17.20 + renderkid: ^3.0.0 + checksum: a5b9137365690104ded6947dca2e33360bf55e62a4acd91b1b0d7baa3970e43754c628cc9e16eafbdd4e8f8bcb260a5865475d4fc17c3106ff2d61db4e72cdf3 + languageName: node + linkType: hard + +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.5.0": + version: 29.5.0 + resolution: "pretty-format@npm:29.5.0" + dependencies: + "@jest/schemas": ^29.4.3 + ansi-styles: ^5.0.0 + react-is: ^18.0.0 + checksum: 4065356b558e6db25b4d41a01efb386935a6c06a0c9c104ef5ce59f2f476b8210edb8b3949b386e60ada0a6dc5ebcb2e6ccddc8c64dfd1a9943c3c3a9e7eaf89 + languageName: node + linkType: hard + +"proc-log@npm:^3.0.0": + version: 3.0.0 + resolution: "proc-log@npm:3.0.0" + checksum: 02b64e1b3919e63df06f836b98d3af002b5cd92655cab18b5746e37374bfb73e03b84fe305454614b34c25b485cc687a9eebdccf0242cda8fda2475dd2c97e02 + languageName: node + linkType: hard + +"process-nextick-args@npm:~2.0.0": + version: 2.0.1 + resolution: "process-nextick-args@npm:2.0.1" + checksum: 1d38588e520dab7cea67cbbe2efdd86a10cc7a074c09657635e34f035277b59fbb57d09d8638346bf7090f8e8ebc070c96fa5fd183b777fff4f5edff5e9466cf + languageName: node + linkType: hard + +"process-warning@npm:1.0.0, process-warning@npm:^1.0.0": + version: 1.0.0 + resolution: "process-warning@npm:1.0.0" + checksum: c708a03241deec3cabaeee39c4f9ee8c4d71f1c5ef9b746c8252cdb952a6059068cfcdaf348399775244cbc441b6ae5e26a9c87ed371f88335d84f26d19180f9 + languageName: node + linkType: hard + +"process@npm:^0.11.1, process@npm:^0.11.10": + version: 0.11.10 + resolution: "process@npm:0.11.10" + checksum: bfcce49814f7d172a6e6a14d5fa3ac92cc3d0c3b9feb1279774708a719e19acd673995226351a082a9ae99978254e320ccda4240ddc474ba31a76c79491ca7c3 + languageName: node + linkType: hard + +"promise-deferred@npm:^2.0.3": + version: 2.0.3 + resolution: "promise-deferred@npm:2.0.3" + dependencies: + promise: ^7.3.1 + checksum: 2e640ddd1e21da2543d66e589d6fa970eca8fa3a1e88629db3cd095cb77427536cdc426646bd092f6db05ff5e28e29f0ad87fb4e44d7529af9914e8e4b9e9899 + languageName: node + linkType: hard + +"promise-inflight@npm:^1.0.1": + version: 1.0.1 + resolution: "promise-inflight@npm:1.0.1" + checksum: 22749483091d2c594261517f4f80e05226d4d5ecc1fc917e1886929da56e22b5718b7f2a75f3807e7a7d471bc3be2907fe92e6e8f373ddf5c64bae35b5af3981 + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: ^2.0.2 + retry: ^0.12.0 + checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 + languageName: node + linkType: hard + +"promise@npm:^7.3.1": + version: 7.3.1 + resolution: "promise@npm:7.3.1" + dependencies: + asap: ~2.0.3 + checksum: 475bb069130179fbd27ed2ab45f26d8862376a137a57314cf53310bdd85cc986a826fd585829be97ebc0aaf10e9d8e68be1bfe5a4a0364144b1f9eedfa940cf1 + languageName: node + linkType: hard + +"promiseback@npm:^2.0.2": + version: 2.0.3 + resolution: "promiseback@npm:2.0.3" + dependencies: + is-callable: ^1.1.5 + promise-deferred: ^2.0.3 + checksum: c4d75176df643be766cd11fca2df38fac83e62a1c5a9e3d5c89acb4d32080ce7f14c74b6794e8ea1d15687edb88df60404882105a47e27aecfa7e45800f68464 + languageName: node + linkType: hard + +"prompts@npm:^2.0.1": + version: 2.4.2 + resolution: "prompts@npm:2.4.2" + dependencies: + kleur: ^3.0.3 + sisteransi: ^1.0.5 + checksum: d8fd1fe63820be2412c13bfc5d0a01909acc1f0367e32396962e737cb2fc52d004f3302475d5ce7d18a1e8a79985f93ff04ee03007d091029c3f9104bffc007d + languageName: node + linkType: hard + +"promzard@npm:^1.0.0": + version: 1.0.0 + resolution: "promzard@npm:1.0.0" + dependencies: + read: ^2.0.0 + checksum: c06948827171612faae321ebaf23ff8bd9ebb3e1e0f37616990bc4b81c663b192e447b3fe3b424211beb0062cec0cfe6ba3ce70c8b448b4aa59752b765dbb302 + languageName: node + linkType: hard + +"prop-types@npm:^15.5.8, prop-types@npm:^15.6.1, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": + version: 15.8.1 + resolution: "prop-types@npm:15.8.1" + dependencies: + loose-envify: ^1.4.0 + object-assign: ^4.1.1 + react-is: ^16.13.1 + checksum: c056d3f1c057cb7ff8344c645450e14f088a915d078dcda795041765047fa080d38e5d626560ccaac94a4e16e3aa15f3557c1a9a8d1174530955e992c675e459 + languageName: node + linkType: hard + +"property-expr@npm:^2.0.4": + version: 2.0.5 + resolution: "property-expr@npm:2.0.5" + checksum: 4ebe82ce45aaf1527e96e2ab84d75d25217167ec3ff6378cf83a84fb4abc746e7c65768a79d275881602ae82f168f9a6dfaa7f5e331d0fcc83d692770bcce5f1 + languageName: node + linkType: hard + +"protocols@npm:^2.0.0, protocols@npm:^2.0.1": + version: 2.0.1 + resolution: "protocols@npm:2.0.1" + checksum: 4a9bef6aa0449a0245ded319ac3cbfd032c3e76ebb562777037a3a832c99253d0e8bc2847f7be350236df620a11f7d4fe683ea7f59a2cc14c69f746b6259eda4 + languageName: node + linkType: hard + +"proxy-addr@npm:~2.0.7": + version: 2.0.7 + resolution: "proxy-addr@npm:2.0.7" + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + checksum: 29c6990ce9364648255454842f06f8c46fcd124d3e6d7c5066df44662de63cdc0bad032e9bf5a3d653ff72141cc7b6019873d685708ac8210c30458ad99f2b74 + languageName: node + linkType: hard + +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 + languageName: node + linkType: hard + +"psl@npm:^1.1.28, psl@npm:^1.1.33": + version: 1.9.0 + resolution: "psl@npm:1.9.0" + checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d + languageName: node + linkType: hard + +"pump@npm:^3.0.0": + version: 3.0.0 + resolution: "pump@npm:3.0.0" + dependencies: + end-of-stream: ^1.1.0 + once: ^1.3.1 + checksum: e42e9229fba14732593a718b04cb5e1cfef8254544870997e0ecd9732b189a48e1256e4e5478148ecb47c8511dca2b09eae56b4d0aad8009e6fac8072923cfc9 + languageName: node + linkType: hard + +"punycode@npm:^2.1.0, punycode@npm:^2.1.1": + version: 2.3.0 + resolution: "punycode@npm:2.3.0" + checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 + languageName: node + linkType: hard + +"pure-rand@npm:^6.0.0": + version: 6.0.0 + resolution: "pure-rand@npm:6.0.0" + checksum: ad1378d0a4859482d053a5264b2b485b445ece4bbc56f8959c233ea678b81ac2d613737925d496ded134eff5f29cc5546bf7492b6bce319ee27bebbad8a0c612 + languageName: node + linkType: hard + +"qs@npm:6.11.0": + version: 6.11.0 + resolution: "qs@npm:6.11.0" + dependencies: + side-channel: ^1.0.4 + checksum: 6e1f29dd5385f7488ec74ac7b6c92f4d09a90408882d0c208414a34dd33badc1a621019d4c799a3df15ab9b1d0292f97c1dd71dc7c045e69f81a8064e5af7297 + languageName: node + linkType: hard + +"qs@npm:~6.5.2": + version: 6.5.3 + resolution: "qs@npm:6.5.3" + checksum: 6f20bf08cabd90c458e50855559539a28d00b2f2e7dddcb66082b16a43188418cb3cb77cbd09268bcef6022935650f0534357b8af9eeb29bf0f27ccb17655692 + languageName: node + linkType: hard + +"querystringify@npm:^2.1.1": + version: 2.2.0 + resolution: "querystringify@npm:2.2.0" + checksum: 5641ea231bad7ef6d64d9998faca95611ed4b11c2591a8cae741e178a974f6a8e0ebde008475259abe1621cb15e692404e6b6626e927f7b849d5c09392604b15 + languageName: node + linkType: hard + +"queue-microtask@npm:^1.2.2": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 + languageName: node + linkType: hard + +"quick-format-unescaped@npm:^4.0.3": + version: 4.0.4 + resolution: "quick-format-unescaped@npm:4.0.4" + checksum: 7bc32b99354a1aa46c089d2a82b63489961002bb1d654cee3e6d2d8778197b68c2d854fd23d8422436ee1fdfd0abaddc4d4da120afe700ade68bd357815b26fd + languageName: node + linkType: hard + +"quick-lru@npm:^4.0.1": + version: 4.0.1 + resolution: "quick-lru@npm:4.0.1" + checksum: bea46e1abfaa07023e047d3cf1716a06172c4947886c053ede5c50321893711577cb6119360f810cc3ffcd70c4d7db4069c3cee876b358ceff8596e062bd1154 + languageName: node + linkType: hard + +"quick-lru@npm:^5.1.1": + version: 5.1.1 + resolution: "quick-lru@npm:5.1.1" + checksum: a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed + languageName: node + linkType: hard + +"randombytes@npm:^2.1.0": + version: 2.1.0 + resolution: "randombytes@npm:2.1.0" + dependencies: + safe-buffer: ^5.1.0 + checksum: d779499376bd4cbb435ef3ab9a957006c8682f343f14089ed5f27764e4645114196e75b7f6abf1cbd84fd247c0cb0651698444df8c9bf30e62120fbbc52269d6 + languageName: node + linkType: hard + +"range-parser@npm:~1.2.1": + version: 1.2.1 + resolution: "range-parser@npm:1.2.1" + checksum: 0a268d4fea508661cf5743dfe3d5f47ce214fd6b7dec1de0da4d669dd4ef3d2144468ebe4179049eff253d9d27e719c88dae55be64f954e80135a0cada804ec9 + languageName: node + linkType: hard + +"raw-body@npm:2.5.1": + version: 2.5.1 + resolution: "raw-body@npm:2.5.1" + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + checksum: 5362adff1575d691bb3f75998803a0ffed8c64eabeaa06e54b4ada25a0cd1b2ae7f4f5ec46565d1bec337e08b5ac90c76eaa0758de6f72a633f025d754dec29e + languageName: node + linkType: hard + +"raw-body@npm:2.5.2": + version: 2.5.2 + resolution: "raw-body@npm:2.5.2" + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + checksum: ba1583c8d8a48e8fbb7a873fdbb2df66ea4ff83775421bfe21ee120140949ab048200668c47d9ae3880012f6e217052690628cf679ddfbd82c9fc9358d574676 + languageName: node + linkType: hard + +"rc@npm:1.2.8, rc@npm:^1.2.8": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: ^0.6.0 + ini: ~1.3.0 + minimist: ^1.2.0 + strip-json-comments: ~2.0.1 + bin: + rc: ./cli.js + checksum: 2e26e052f8be2abd64e6d1dabfbd7be03f80ec18ccbc49562d31f617d0015fbdbcf0f9eed30346ea6ab789e0fdfe4337f033f8016efdbee0df5354751842080e + languageName: node + linkType: hard + +"react-base16-styling@npm:^0.9.1": + version: 0.9.1 + resolution: "react-base16-styling@npm:0.9.1" + dependencies: + "@babel/runtime": ^7.16.7 + "@types/base16": ^1.0.2 + "@types/lodash": ^4.14.178 + base16: ^1.0.0 + color: ^3.2.1 + csstype: ^3.0.10 + lodash.curry: ^4.1.1 + checksum: 1e61e1158ee5250ad68860840368f9228685680df15385c0fc4d5c63dd0925f27f4f1d1762134de623fe005e75ef9543191aa648cde2c16d0153341d00ceeecb + languageName: node + linkType: hard + +"react-dom@npm:^18.2.0": + version: 18.2.0 + resolution: "react-dom@npm:18.2.0" + dependencies: + loose-envify: ^1.1.0 + scheduler: ^0.23.0 + peerDependencies: + react: ^18.2.0 + checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc + languageName: node + linkType: hard + +"react-highlight-words@npm:^0.20.0": + version: 0.20.0 + resolution: "react-highlight-words@npm:0.20.0" + dependencies: + highlight-words-core: ^1.2.0 + memoize-one: ^4.0.0 + prop-types: ^15.5.8 + peerDependencies: + react: ^0.14.0 || ^15.0.0 || ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 + checksum: 6794b6fe409ee81390e342ccdb951696e06354d8591b4cac050a6d64dbc77dfc7bb636fee0aabcfda841e57778aa5108fe351e7c1dc27b28abedd36aec8141e7 + languageName: node + linkType: hard + +"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.0.0, react-is@npm:^18.2.0": + version: 18.2.0 + resolution: "react-is@npm:18.2.0" + checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e + languageName: node + linkType: hard + +"react-is@npm:^16.13.1": + version: 16.13.1 + resolution: "react-is@npm:16.13.1" + checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f + languageName: node + linkType: hard + +"react-json-tree@npm:^0.18.0": + version: 0.18.0 + resolution: "react-json-tree@npm:0.18.0" + dependencies: + "@babel/runtime": ^7.20.6 + "@types/lodash": ^4.14.191 + react-base16-styling: ^0.9.1 + peerDependencies: + "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: e59244b1f7866a3fec7b5fe83d68833583568e9ae217c261b09077de196a51cc96642e8b1d6826d963aaf910a496e1cf432240ee142ce7efa965345915bb57ac + languageName: node + linkType: hard + +"react-paginate@npm:^6.3.2": + version: 6.5.0 + resolution: "react-paginate@npm:6.5.0" + dependencies: + prop-types: ^15.6.1 + peerDependencies: + react: ^16.0.0 + checksum: 39397de9a330e9ed16b2422d5893f47e16b5f7f188bf59ce4f60beeb16cfdba0ba76c7f0ca1b733d7282821a4e984ae64fb1a7086ecc22b416af95c1ff974fec + languageName: node + linkType: hard + +"react-shallow-renderer@npm:^16.15.0": + version: 16.15.0 + resolution: "react-shallow-renderer@npm:16.15.0" + dependencies: + object-assign: ^4.1.1 + react-is: ^16.12.0 || ^17.0.0 || ^18.0.0 + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 6052c7e3e9627485120ebd8257f128aad8f56386fe8d42374b7743eac1be457c33506d153c7886b4e32923c0c352d402ab805ef9ca02dbcd8393b2bdeb6e5af8 + languageName: node + linkType: hard + +"react-test-renderer@npm:^18.2.0": + version: 18.2.0 + resolution: "react-test-renderer@npm:18.2.0" + dependencies: + react-is: ^18.2.0 + react-shallow-renderer: ^16.15.0 + scheduler: ^0.23.0 + peerDependencies: + react: ^18.2.0 + checksum: 6b6980ced93fa2b72662d5e4ab3b4896833586940047ce52ca9aca801e5432adf05fcbe28289b0af3ce6a2a7c590974e25dcc8aa43d0de658bfe8bbcd686f958 + languageName: node + linkType: hard + +"react-toastify@npm:^9.0.8": + version: 9.1.1 + resolution: "react-toastify@npm:9.1.1" + dependencies: + clsx: ^1.1.1 + peerDependencies: + react: ">=16" + react-dom: ">=16" + checksum: 2039255539961a9b4d77b2656f120b20abe46cb0c699a7f3c0af23b4ef669d9c4d24dae6b8f4954b5efd83edf6d6e23614a29e94e9ee0d2647741fba9ba2db85 + languageName: node + linkType: hard + +"react@npm:^18.2.0": + version: 18.2.0 + resolution: "react@npm:18.2.0" + dependencies: + loose-envify: ^1.1.0 + checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b + languageName: node + linkType: hard + +"read-cmd-shim@npm:4.0.0": + version: 4.0.0 + resolution: "read-cmd-shim@npm:4.0.0" + checksum: 2fb5a8a38984088476f559b17c6a73324a5db4e77e210ae0aab6270480fd85c355fc990d1c79102e25e555a8201606ed12844d6e3cd9f35d6a1518791184e05b + languageName: node + linkType: hard + +"read-package-json-fast@npm:^3.0.0": + version: 3.0.2 + resolution: "read-package-json-fast@npm:3.0.2" + dependencies: + json-parse-even-better-errors: ^3.0.0 + npm-normalize-package-bin: ^3.0.0 + checksum: 8d406869f045f1d76e2a99865a8fd1c1af9c1dc06200b94d2b07eef87ed734b22703a8d72e1cd36ea36cc48e22020bdd187f88243c7dd0563f72114d38c17072 + languageName: node + linkType: hard + +"read-package-json@npm:6.0.4, read-package-json@npm:^6.0.0": + version: 6.0.4 + resolution: "read-package-json@npm:6.0.4" + dependencies: + glob: ^10.2.2 + json-parse-even-better-errors: ^3.0.0 + normalize-package-data: ^5.0.0 + npm-normalize-package-bin: ^3.0.0 + checksum: ce40c4671299753f1349aebe44693cd250d6936c4bacfb31cd884c87f24a0174ba5f651ee2866cf5e57365451cba38bc1db9c2a371e4ba7502fb46dcad50f1d7 + languageName: node + linkType: hard + +"read-pkg-up@npm:^3.0.0": + version: 3.0.0 + resolution: "read-pkg-up@npm:3.0.0" + dependencies: + find-up: ^2.0.0 + read-pkg: ^3.0.0 + checksum: 16175573f2914ab9788897bcbe2a62b5728d0075e62285b3680cebe97059e2911e0134a062cf6e51ebe3e3775312bc788ac2039ed6af38ec68d2c10c6f2b30fb + languageName: node + linkType: hard + +"read-pkg-up@npm:^7.0.1": + version: 7.0.1 + resolution: "read-pkg-up@npm:7.0.1" + dependencies: + find-up: ^4.1.0 + read-pkg: ^5.2.0 + type-fest: ^0.8.1 + checksum: e4e93ce70e5905b490ca8f883eb9e48b5d3cebc6cd4527c25a0d8f3ae2903bd4121c5ab9c5a3e217ada0141098eeb661313c86fa008524b089b8ed0b7f165e44 + languageName: node + linkType: hard + +"read-pkg-up@npm:^8.0.0": + version: 8.0.0 + resolution: "read-pkg-up@npm:8.0.0" + dependencies: + find-up: ^5.0.0 + read-pkg: ^6.0.0 + type-fest: ^1.0.1 + checksum: fe4c80401656b40b408884457fffb5a8015c03b1018cfd8e48f8d82a5e9023e24963603aeb2755608d964593e046c15b34d29b07d35af9c7aa478be81805209c + languageName: node + linkType: hard + +"read-pkg@npm:^3.0.0": + version: 3.0.0 + resolution: "read-pkg@npm:3.0.0" + dependencies: + load-json-file: ^4.0.0 + normalize-package-data: ^2.3.2 + path-type: ^3.0.0 + checksum: 398903ebae6c7e9965419a1062924436cc0b6f516c42c4679a90290d2f87448ed8f977e7aa2dbba4aa1ac09248628c43e493ac25b2bc76640e946035200e34c6 + languageName: node + linkType: hard + +"read-pkg@npm:^5.2.0": + version: 5.2.0 + resolution: "read-pkg@npm:5.2.0" + dependencies: + "@types/normalize-package-data": ^2.4.0 + normalize-package-data: ^2.5.0 + parse-json: ^5.0.0 + type-fest: ^0.6.0 + checksum: eb696e60528b29aebe10e499ba93f44991908c57d70f2d26f369e46b8b9afc208ef11b4ba64f67630f31df8b6872129e0a8933c8c53b7b4daf0eace536901222 + languageName: node + linkType: hard + +"read-pkg@npm:^6.0.0": + version: 6.0.0 + resolution: "read-pkg@npm:6.0.0" + dependencies: + "@types/normalize-package-data": ^2.4.0 + normalize-package-data: ^3.0.2 + parse-json: ^5.2.0 + type-fest: ^1.0.1 + checksum: 0cebdff381128e923815c643074a87011070e5fc352bee575d327d6485da3317fab6d802a7b03deeb0be7be8d3ad1640397b3d5d2f044452caf4e8d1736bf94f + languageName: node + linkType: hard + +"read@npm:^2.0.0": + version: 2.1.0 + resolution: "read@npm:2.1.0" + dependencies: + mute-stream: ~1.0.0 + checksum: e745999138022b56d32daf7cce9b7552b2ec648e4e2578d076a410575a0a400faf74f633dd74ef1b1c42563397d322c1ad5a0068471c38978b02ef97056c2991 + languageName: node + linkType: hard + +"readable-stream@npm:^2.1.4, readable-stream@npm:~2.3.6": + version: 2.3.8 + resolution: "readable-stream@npm:2.3.8" + 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 + checksum: 65645467038704f0c8aaf026a72fbb588a9e2ef7a75cd57a01702ee9db1c4a1e4b03aaad36861a6a0926546a74d174149c8c207527963e0c2d3eee2f37678a42 + languageName: node + linkType: hard + +"readable-stream@npm:^3.0.0, readable-stream@npm:^3.0.2, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: ^2.0.3 + string_decoder: ^1.1.1 + util-deprecate: ^1.0.1 + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + languageName: node + linkType: hard + +"readable-stream@npm:^4.0.0": + version: 4.3.0 + resolution: "readable-stream@npm:4.3.0" + dependencies: + abort-controller: ^3.0.0 + buffer: ^6.0.3 + events: ^3.3.0 + process: ^0.11.10 + checksum: 5f8d5fc1eb0c6eb47771ad4537881126d6280666e1f10ba1e2262a670a0352c36f59e6a04d17c9a6f7c888218984836dc67f55e95a77de8bfdf06fb75f00f670 + languageName: node + linkType: hard + +"readdirp@npm:~3.6.0": + version: 3.6.0 + resolution: "readdirp@npm:3.6.0" + dependencies: + picomatch: ^2.2.1 + checksum: 1ced032e6e45670b6d7352d71d21ce7edf7b9b928494dcaba6f11fba63180d9da6cd7061ebc34175ffda6ff529f481818c962952004d273178acd70f7059b320 + languageName: node + linkType: hard + +"real-require@npm:^0.1.0": + version: 0.1.0 + resolution: "real-require@npm:0.1.0" + checksum: 96745583ed4f82cd5c6a6af012fd1d3c6fc2f13ae1bcff1a3c4f8094696013a1a07c82c5aa66a403d7d4f84949fc2203bc927c7ad120caad125941ca2d7e5e8e + languageName: node + linkType: hard + +"rechoir@npm:^0.8.0": + version: 0.8.0 + resolution: "rechoir@npm:0.8.0" + dependencies: + resolve: ^1.20.0 + checksum: ad3caed8afdefbc33fbc30e6d22b86c35b3d51c2005546f4e79bcc03c074df804b3640ad18945e6bef9ed12caedc035655ec1082f64a5e94c849ff939dc0a788 + languageName: node + linkType: hard + +"redent@npm:^3.0.0": + version: 3.0.0 + resolution: "redent@npm:3.0.0" + dependencies: + indent-string: ^4.0.0 + strip-indent: ^3.0.0 + checksum: fa1ef20404a2d399235e83cc80bd55a956642e37dd197b4b612ba7327bf87fa32745aeb4a1634b2bab25467164ab4ed9c15be2c307923dd08b0fe7c52431ae6b + languageName: node + linkType: hard + +"redent@npm:^4.0.0": + version: 4.0.0 + resolution: "redent@npm:4.0.0" + dependencies: + indent-string: ^5.0.0 + strip-indent: ^4.0.0 + checksum: 6944e7b1d8f3fd28c2515f5c605b9f7f0ea0f4edddf41890bbbdd4d9ee35abb7540c3b278f03ff827bd278bb6ff4a5bd8692ca406b748c5c1c3ce7355e9fbf8f + languageName: node + linkType: hard + +"regenerate-unicode-properties@npm:^10.1.0": + version: 10.1.0 + resolution: "regenerate-unicode-properties@npm:10.1.0" + dependencies: + regenerate: ^1.4.2 + checksum: b1a8929588433ab8b9dc1a34cf3665b3b472f79f2af6ceae00d905fc496b332b9af09c6718fb28c730918f19a00dc1d7310adbaa9b72a2ec7ad2f435da8ace17 + languageName: node + linkType: hard + +"regenerate@npm:^1.4.2": + version: 1.4.2 + resolution: "regenerate@npm:1.4.2" + checksum: 3317a09b2f802da8db09aa276e469b57a6c0dd818347e05b8862959c6193408242f150db5de83c12c3fa99091ad95fb42a6db2c3329bfaa12a0ea4cbbeb30cb0 + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.13.11": + version: 0.13.11 + resolution: "regenerator-runtime@npm:0.13.11" + checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 + languageName: node + linkType: hard + +"regenerator-transform@npm:^0.15.1": + version: 0.15.1 + resolution: "regenerator-transform@npm:0.15.1" + dependencies: + "@babel/runtime": ^7.8.4 + checksum: 2d15bdeadbbfb1d12c93f5775493d85874dbe1d405bec323da5c61ec6e701bc9eea36167483e1a5e752de9b2df59ab9a2dfff6bf3784f2b28af2279a673d29a4 + languageName: node + linkType: hard + +"regexp-match-indices@npm:^1.0.2": + version: 1.0.2 + resolution: "regexp-match-indices@npm:1.0.2" + dependencies: + regexp-tree: ^0.1.11 + checksum: 8cc779f6cf8f404ead828d09970a7d4bd66bd78d43ab9eb2b5e65f2ef2ba1ed53536f5b5fa839fb90b350365fb44b6a851c7f16289afc3f37789c113ab2a7916 + languageName: node + linkType: hard + +"regexp-to-ast@npm:0.5.0": + version: 0.5.0 + resolution: "regexp-to-ast@npm:0.5.0" + checksum: 72e32f2a1217bb22398ac30867ddd43e16943b6b569dd4eb472de47494c7a39e34f47ee3e92ad4cbf92308f98997da366fe094a0e58eb6b93eab0ee956fff86d + languageName: node + linkType: hard + +"regexp-tree@npm:^0.1.11": + version: 0.1.24 + resolution: "regexp-tree@npm:0.1.24" + bin: + regexp-tree: bin/regexp-tree + checksum: 5807013289d9205288d665e0f8d8cff94843dfd55fdedd1833eb9d9bbd07188a37dfa02942ec5cdc671180037f715148fac1ba6f18fd6be4268e5a8feb49d340 + languageName: node + linkType: hard + +"regexp.prototype.flags@npm:^1.4.3": + version: 1.4.3 + resolution: "regexp.prototype.flags@npm:1.4.3" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + functions-have-names: ^1.2.2 + checksum: 51228bae732592adb3ededd5e15426be25f289e9c4ef15212f4da73f4ec3919b6140806374b8894036a86020d054a8d2657d3fee6bb9b4d35d8939c20030b7a6 + languageName: node + linkType: hard + +"regexpu-core@npm:^5.3.1": + version: 5.3.1 + resolution: "regexpu-core@npm:5.3.1" + dependencies: + "@babel/regjsgen": ^0.8.0 + regenerate: ^1.4.2 + regenerate-unicode-properties: ^10.1.0 + regjsparser: ^0.9.1 + unicode-match-property-ecmascript: ^2.0.0 + unicode-match-property-value-ecmascript: ^2.1.0 + checksum: 446fbbb79059afcd64d11ea573276e2df97ee7ad45aa452834d3b2aef7edf7bfe206c310f57f9345d8c95bfedbf9c16a9529f9219a05ae6a6b0d6f0dbe523b33 + languageName: node + linkType: hard + +"registry-auth-token@npm:^4.0.0": + version: 4.2.2 + resolution: "registry-auth-token@npm:4.2.2" + dependencies: + rc: 1.2.8 + checksum: c5030198546ecfdcbcb0722cbc3e260c4f5f174d8d07bdfedd4620e79bfdf17a2db735aa230d600bd388fce6edd26c0a9ed2eb7e9b4641ec15213a28a806688b + languageName: node + linkType: hard + +"registry-url@npm:^5.0.0": + version: 5.1.0 + resolution: "registry-url@npm:5.1.0" + dependencies: + rc: ^1.2.8 + checksum: bcea86c84a0dbb66467b53187fadebfea79017cddfb4a45cf27530d7275e49082fe9f44301976eb0164c438e395684bcf3dae4819b36ff9d1640d8cc60c73df9 + languageName: node + linkType: hard + +"regjsparser@npm:^0.9.1": + version: 0.9.1 + resolution: "regjsparser@npm:0.9.1" + dependencies: + jsesc: ~0.5.0 + bin: + regjsparser: bin/parser + checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc + languageName: node + linkType: hard + +"relateurl@npm:^0.2.7": + version: 0.2.7 + resolution: "relateurl@npm:0.2.7" + checksum: 5891e792eae1dfc3da91c6fda76d6c3de0333a60aa5ad848982ebb6dccaa06e86385fb1235a1582c680a3d445d31be01c6bfc0804ebbcab5aaf53fa856fde6b6 + languageName: node + linkType: hard + +"renderkid@npm:^3.0.0": + version: 3.0.0 + resolution: "renderkid@npm:3.0.0" + dependencies: + css-select: ^4.1.3 + dom-converter: ^0.2.0 + htmlparser2: ^6.1.0 + lodash: ^4.17.21 + strip-ansi: ^6.0.1 + checksum: 77162b62d6f33ab81f337c39efce0439ff0d1f6d441e29c35183151f83041c7850774fb904da163d6c844264d440d10557714e6daa0b19e4561a5cd4ef305d41 + languageName: node + linkType: hard + +"request@npm:2.88.2": + version: 2.88.2 + resolution: "request@npm:2.88.2" + 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 + checksum: 4e112c087f6eabe7327869da2417e9d28fcd0910419edd2eb17b6acfc4bfa1dad61954525949c228705805882d8a98a86a0ea12d7f739c01ee92af7062996983 + languageName: node + linkType: hard + +"require-directory@npm:^2.1.1": + version: 2.1.1 + resolution: "require-directory@npm:2.1.1" + checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 + languageName: node + linkType: hard + +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b + languageName: node + linkType: hard + +"requires-port@npm:^1.0.0": + version: 1.0.0 + resolution: "requires-port@npm:1.0.0" + checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff + languageName: node + linkType: hard + +"resolve-alpn@npm:^1.0.0": + version: 1.2.1 + resolution: "resolve-alpn@npm:1.2.1" + checksum: f558071fcb2c60b04054c99aebd572a2af97ef64128d59bef7ab73bd50d896a222a056de40ffc545b633d99b304c259ea9d0c06830d5c867c34f0bfa60b8eae0 + languageName: node + linkType: hard + +"resolve-cwd@npm:^3.0.0": + version: 3.0.0 + resolution: "resolve-cwd@npm:3.0.0" + dependencies: + resolve-from: ^5.0.0 + checksum: 546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 + languageName: node + linkType: hard + +"resolve-from@npm:5.0.0, resolve-from@npm:^5.0.0": + version: 5.0.0 + resolution: "resolve-from@npm:5.0.0" + checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf + languageName: node + linkType: hard + +"resolve-from@npm:^4.0.0": + version: 4.0.0 + resolution: "resolve-from@npm:4.0.0" + checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f + languageName: node + linkType: hard + +"resolve.exports@npm:^2.0.0": + version: 2.0.1 + resolution: "resolve.exports@npm:2.0.1" + checksum: 03be177026b4fe8dc1b2ffb421bce9cbf7fe3446e9f0c958df9fc8e144864b3eeea19fe788e057fd8be6b5655e65ce245b4f379258c1336e2e8f9205cbd4a9b4 + languageName: node + linkType: hard + +"resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.20.0": + version: 1.22.1 + resolution: "resolve@npm:1.22.1" + dependencies: + is-core-module: ^2.9.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 07af5fc1e81aa1d866cbc9e9460fbb67318a10fa3c4deadc35c3ad8a898ee9a71a86a65e4755ac3195e0ea0cfbe201eb323ebe655ce90526fd61917313a34e4e + languageName: node + linkType: hard + +"resolve@npm:^2.0.0-next.4": + version: 2.0.0-next.4 + resolution: "resolve@npm:2.0.0-next.4" + dependencies: + is-core-module: ^2.9.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: c438ac9a650f2030fd074219d7f12ceb983b475da2d89ad3d6dd05fbf6b7a0a8cd37d4d10b43cb1f632bc19f22246ab7f36ebda54d84a29bfb2910a0680906d3 + languageName: node + linkType: hard + +"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.20.0#~builtin": + version: 1.22.1 + resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&hash=c3c19d" + dependencies: + is-core-module: ^2.9.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 5656f4d0bedcf8eb52685c1abdf8fbe73a1603bb1160a24d716e27a57f6cecbe2432ff9c89c2bd57542c3a7b9d14b1882b73bfe2e9d7849c9a4c0b8b39f02b8b + languageName: node + linkType: hard + +"resolve@patch:resolve@^2.0.0-next.4#~builtin": + version: 2.0.0-next.4 + resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=c3c19d" + dependencies: + is-core-module: ^2.9.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 4bf9f4f8a458607af90518ff73c67a4bc1a38b5a23fef2bb0ccbd45e8be89820a1639b637b0ba377eb2be9eedfb1739a84cde24fe4cd670c8207d8fea922b011 + languageName: node + linkType: hard + +"responselike@npm:^2.0.0": + version: 2.0.1 + resolution: "responselike@npm:2.0.1" + dependencies: + lowercase-keys: ^2.0.0 + checksum: b122535466e9c97b55e69c7f18e2be0ce3823c5d47ee8de0d9c0b114aa55741c6db8bfbfce3766a94d1272e61bfb1ebf0a15e9310ac5629fbb7446a861b4fd3a + languageName: node + linkType: hard + +"restore-cursor@npm:^3.1.0": + version: 3.1.0 + resolution: "restore-cursor@npm:3.1.0" + dependencies: + onetime: ^5.1.0 + signal-exit: ^3.0.2 + checksum: f877dd8741796b909f2a82454ec111afb84eb45890eb49ac947d87991379406b3b83ff9673a46012fca0d7844bb989f45cc5b788254cf1a39b6b5a9659de0630 + languageName: node + linkType: hard + +"restore-cursor@npm:^4.0.0": + version: 4.0.0 + resolution: "restore-cursor@npm:4.0.0" + dependencies: + onetime: ^5.1.0 + signal-exit: ^3.0.2 + checksum: 5b675c5a59763bf26e604289eab35711525f11388d77f409453904e1e69c0d37ae5889295706b2c81d23bd780165084d040f9b68fffc32cc921519031c4fa4af + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c + languageName: node + linkType: hard + +"reusify@npm:^1.0.4": + version: 1.0.4 + resolution: "reusify@npm:1.0.4" + checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc + languageName: node + linkType: hard + +"rimraf@npm:^3.0.0, rimraf@npm:^3.0.2, rimraf@npm:~3.0.0": + version: 3.0.2 + resolution: "rimraf@npm:3.0.2" + dependencies: + glob: ^7.1.3 + bin: + rimraf: bin.js + checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 + languageName: node + linkType: hard + +"rimraf@npm:^4.4.1": + version: 4.4.1 + resolution: "rimraf@npm:4.4.1" + dependencies: + glob: ^9.2.0 + bin: + rimraf: dist/cjs/src/bin.js + checksum: b786adc02651e2e24bbedb04bbdea80652fc9612632931ff2d9f898c5e4708fe30956186597373c568bd5230a4dc2fadfc816ccacba8a1daded3a006a6b74f1a + languageName: node + linkType: hard + +"rimraf@npm:~2.4.0": + version: 2.4.5 + resolution: "rimraf@npm:2.4.5" + dependencies: + glob: ^6.0.1 + bin: + rimraf: ./bin.js + checksum: 036793b4055d65344ad7bea73c3f4095640af7455478fe56c19783619463e6bb4374ab3556b9e6d4d6d3dd210eb677b0955ece38813e734c294fd2687201151d + languageName: node + linkType: hard + +"robust-predicates@npm:^3.0.0": + version: 3.0.1 + resolution: "robust-predicates@npm:3.0.1" + checksum: 45e9de2df4380da84a2a561d4fd54ea92194e878b93ed19d5e4bc90f4e834a13755e846c8516bab8360190309696f0564a0150386c52ef01f70f2b388449dac5 + languageName: node + linkType: hard + +"run-applescript@npm:^5.0.0": + version: 5.0.0 + resolution: "run-applescript@npm:5.0.0" + dependencies: + execa: ^5.0.0 + checksum: d00c2dbfa5b2d774de7451194b8b125f40f65fc183de7d9dcae97f57f59433586d3c39b9001e111c38bfa24c3436c99df1bb4066a2a0c90d39a8c4cd6889af77 + languageName: node + linkType: hard + +"run-async@npm:^2.4.0": + version: 2.4.1 + resolution: "run-async@npm:2.4.1" + checksum: a2c88aa15df176f091a2878eb840e68d0bdee319d8d97bbb89112223259cebecb94bc0defd735662b83c2f7a30bed8cddb7d1674eb48ae7322dc602b22d03797 + languageName: node + linkType: hard + +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" + dependencies: + queue-microtask: ^1.2.2 + checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d + languageName: node + linkType: hard + +"rw@npm:1": + version: 1.3.3 + resolution: "rw@npm:1.3.3" + checksum: c20d82421f5a71c86a13f76121b751553a99cd4a70ea27db86f9b23f33db941f3f06019c30f60d50c356d0bd674c8e74764ac146ea55e217c091bde6fba82aa3 + languageName: node + linkType: hard + +"rxjs@npm:^7.2.0, rxjs@npm:^7.5.5, rxjs@npm:^7.5.7": + version: 7.8.0 + resolution: "rxjs@npm:7.8.0" + dependencies: + tslib: ^2.1.0 + checksum: 61b4d4fd323c1043d8d6ceb91f24183b28bcf5def4f01ca111511d5c6b66755bc5578587fe714ef5d67cf4c9f2e26f4490d4e1d8cabf9bd5967687835e9866a2 + languageName: node + linkType: hard + +"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": + version: 5.1.2 + resolution: "safe-buffer@npm:5.1.2" + checksum: f2f1f7943ca44a594893a852894055cf619c1fbcb611237fc39e461ae751187e7baf4dc391a72125e0ac4fb2d8c5c0b3c71529622e6a58f46b960211e704903c + languageName: node + linkType: hard + +"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.2": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + languageName: node + linkType: hard + +"safe-regex-test@npm:^1.0.0": + version: 1.0.0 + resolution: "safe-regex-test@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.1.3 + is-regex: ^1.1.4 + checksum: bc566d8beb8b43c01b94e67de3f070fd2781685e835959bbbaaec91cc53381145ca91f69bd837ce6ec244817afa0a5e974fc4e40a2957f0aca68ac3add1ddd34 + languageName: node + linkType: hard + +"safe-stable-stringify@npm:^2.1.0": + version: 2.4.2 + resolution: "safe-stable-stringify@npm:2.4.2" + checksum: 0324ba2e40f78cae63e31a02b1c9bdf1b786621f9e8760845608eb9e81aef401944ac2078e5c9c1533cf516aea34d08fa8052ca853637ced84b791caaf1e394e + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 + languageName: node + linkType: hard + +"sanitize-html@npm:~2.7.3": + version: 2.7.3 + resolution: "sanitize-html@npm:2.7.3" + dependencies: + deepmerge: ^4.2.2 + escape-string-regexp: ^4.0.0 + htmlparser2: ^6.0.0 + is-plain-object: ^5.0.0 + parse-srcset: ^1.0.2 + postcss: ^8.3.11 + checksum: 2399d1fdbbc3a263fb413c1fe1971b3dc2b51abc6cc5cb49490624539d1c57a8fe31e2b21408c118e2a957f4e673e3169b1f9a5807654408f17b130a9d78aed7 + languageName: node + linkType: hard + +"saxes@npm:^6.0.0": + version: 6.0.0 + resolution: "saxes@npm:6.0.0" + dependencies: + xmlchars: ^2.2.0 + checksum: d3fa3e2aaf6c65ed52ee993aff1891fc47d5e47d515164b5449cbf5da2cbdc396137e55590472e64c5c436c14ae64a8a03c29b9e7389fc6f14035cf4e982ef3b + languageName: node + linkType: hard + +"scheduler@npm:^0.23.0": + version: 0.23.0 + resolution: "scheduler@npm:0.23.0" + dependencies: + loose-envify: ^1.1.0 + checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a + languageName: node + linkType: hard + +"schema-utils@npm:^2.7.0": + version: 2.7.1 + resolution: "schema-utils@npm:2.7.1" + dependencies: + "@types/json-schema": ^7.0.5 + ajv: ^6.12.4 + ajv-keywords: ^3.5.2 + checksum: 32c62fc9e28edd101e1bd83453a4216eb9bd875cc4d3775e4452b541908fa8f61a7bbac8ffde57484f01d7096279d3ba0337078e85a918ecbeb72872fb09fb2b + languageName: node + linkType: hard + +"schema-utils@npm:^3.0.0, schema-utils@npm:^3.1.0, schema-utils@npm:^3.1.1": + version: 3.1.1 + resolution: "schema-utils@npm:3.1.1" + dependencies: + "@types/json-schema": ^7.0.8 + ajv: ^6.12.5 + ajv-keywords: ^3.5.2 + checksum: fb73f3d759d43ba033c877628fe9751620a26879f6301d3dbeeb48cf2a65baec5cdf99da65d1bf3b4ff5444b2e59cbe4f81c2456b5e0d2ba7d7fd4aed5da29ce + languageName: node + linkType: hard + +"schema-utils@npm:^4.0.0": + version: 4.0.0 + resolution: "schema-utils@npm:4.0.0" + dependencies: + "@types/json-schema": ^7.0.9 + ajv: ^8.8.0 + ajv-formats: ^2.1.1 + ajv-keywords: ^5.0.0 + checksum: c843e92fdd1a5c145dbb6ffdae33e501867f9703afac67bdf35a685e49f85b1dcc10ea250033175a64bd9d31f0555bc6785b8359da0c90bcea30cf6dfbb55a8f + languageName: node + linkType: hard + +"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1, semver@npm:^5.6.0": + version: 5.7.1 + resolution: "semver@npm:5.7.1" + bin: + semver: ./bin/semver + checksum: 57fd0acfd0bac382ee87cd52cd0aaa5af086a7dc8d60379dfe65fea491fb2489b6016400813930ecd61fd0952dae75c115287a1b16c234b1550887117744dfaf + languageName: node + linkType: hard + +"semver@npm:7.5.0": + version: 7.5.0 + resolution: "semver@npm:7.5.0" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 2d266937756689a76f124ffb4c1ea3e1bbb2b263219f90ada8a11aebebe1280b13bb76cca2ca96bdee3dbc554cbc0b24752eb895b2a51577aa644427e9229f2b + languageName: node + linkType: hard + +"semver@npm:7.5.1": + version: 7.5.1 + resolution: "semver@npm:7.5.1" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: d16dbedad53c65b086f79524b9ef766bf38670b2395bdad5c957f824dcc566b624988013564f4812bcace3f9d405355c3635e2007396a39d1bffc71cfec4a2fc + languageName: node + linkType: hard + +"semver@npm:7.5.3, semver@npm:7.x, semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8": + version: 7.5.3 + resolution: "semver@npm:7.5.3" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 9d58db16525e9f749ad0a696a1f27deabaa51f66e91d2fa2b0db3de3e9644e8677de3b7d7a03f4c15bc81521e0c3916d7369e0572dbde250d9bedf5194e2a8a7 + languageName: node + linkType: hard + +"semver@npm:^6.0.0, semver@npm:^6.1.1, semver@npm:^6.1.2, semver@npm:^6.3.0": + version: 6.3.0 + resolution: "semver@npm:6.3.0" + bin: + semver: ./bin/semver.js + checksum: 1b26ecf6db9e8292dd90df4e781d91875c0dcc1b1909e70f5d12959a23c7eebb8f01ea581c00783bbee72ceeaad9505797c381756326073850dc36ed284b21b9 + languageName: node + linkType: hard + +"send@npm:0.18.0": + version: 0.18.0 + resolution: "send@npm:0.18.0" + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + etag: ~1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: ~1.2.1 + statuses: 2.0.1 + checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 + languageName: node + linkType: hard + +"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.1": + version: 6.0.1 + resolution: "serialize-javascript@npm:6.0.1" + dependencies: + randombytes: ^2.1.0 + checksum: 3c4f4cb61d0893b988415bdb67243637333f3f574e9e9cc9a006a2ced0b390b0b3b44aef8d51c951272a9002ec50885eefdc0298891bc27eb2fe7510ea87dc4f + languageName: node + linkType: hard + +"serve-static@npm:1.15.0": + version: 1.15.0 + resolution: "serve-static@npm:1.15.0" + dependencies: + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + parseurl: ~1.3.3 + send: 0.18.0 + checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d + languageName: node + linkType: hard + +"set-blocking@npm:^2.0.0": + version: 2.0.0 + resolution: "set-blocking@npm:2.0.0" + checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 + languageName: node + linkType: hard + +"setprototypeof@npm:1.2.0": + version: 1.2.0 + resolution: "setprototypeof@npm:1.2.0" + checksum: be18cbbf70e7d8097c97f713a2e76edf84e87299b40d085c6bf8b65314e994cc15e2e317727342fa6996e38e1f52c59720b53fe621e2eb593a6847bf0356db89 + languageName: node + linkType: hard + +"shallow-clone@npm:^3.0.0": + version: 3.0.1 + resolution: "shallow-clone@npm:3.0.1" + dependencies: + kind-of: ^6.0.2 + checksum: 39b3dd9630a774aba288a680e7d2901f5c0eae7b8387fc5c8ea559918b29b3da144b7bdb990d7ccd9e11be05508ac9e459ce51d01fd65e583282f6ffafcba2e7 + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: ^3.0.0 + checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 + languageName: node + linkType: hard + +"shiki@npm:^0.14.1": + version: 0.14.1 + resolution: "shiki@npm:0.14.1" + dependencies: + ansi-sequence-parser: ^1.1.0 + jsonc-parser: ^3.2.0 + vscode-oniguruma: ^1.7.0 + vscode-textmate: ^8.0.0 + checksum: b19ea337cc84da69d99ca39d109f82946e0c56c11cc4c67b3b91cc14a9479203365fd0c9e0dd87e908f493ab409dc6f1849175384b6ca593ce7da884ae1edca2 + languageName: node + linkType: hard + +"side-channel@npm:^1.0.4": + version: 1.0.4 + resolution: "side-channel@npm:1.0.4" + dependencies: + call-bind: ^1.0.0 + get-intrinsic: ^1.0.2 + object-inspect: ^1.9.0 + checksum: 351e41b947079c10bd0858364f32bb3a7379514c399edb64ab3dce683933483fc63fb5e4efe0a15a2e8a7e3c436b6a91736ddb8d8c6591b0460a24bb4a1ee245 + languageName: node + linkType: hard + +"signal-exit@npm:3.0.7, signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 + languageName: node + linkType: hard + +"signal-exit@npm:^4.0.1": + version: 4.0.2 + resolution: "signal-exit@npm:4.0.2" + checksum: 41f5928431cc6e91087bf0343db786a6313dd7c6fd7e551dbc141c95bb5fb26663444fd9df8ea47c5d7fc202f60aa7468c3162a9365cbb0615fc5e1b1328fe31 + languageName: node + linkType: hard + +"sigstore@npm:^1.3.0, sigstore@npm:^1.4.0": + version: 1.6.0 + resolution: "sigstore@npm:1.6.0" + dependencies: + "@sigstore/protobuf-specs": ^0.1.0 + "@sigstore/tuf": ^1.0.0 + make-fetch-happen: ^11.0.1 + tuf-js: ^1.1.3 + bin: + sigstore: bin/sigstore.js + checksum: 55d87e24fc39ace705ba196bdb94f97bfa06d73887184cc6fc6c3c9b1900f72fed31d550445786b5fd73381e3161dab48065a1d1bdf45298f48d06b0a8ea6899 + languageName: node + linkType: hard + +"simple-concat@npm:^1.0.0": + version: 1.0.1 + resolution: "simple-concat@npm:1.0.1" + checksum: 4d211042cc3d73a718c21ac6c4e7d7a0363e184be6a5ad25c8a1502e49df6d0a0253979e3d50dbdd3f60ef6c6c58d756b5d66ac1e05cda9cacd2e9fc59e3876a + languageName: node + linkType: hard + +"simple-get@npm:^3.0.3": + version: 3.1.1 + resolution: "simple-get@npm:3.1.1" + dependencies: + decompress-response: ^4.2.0 + once: ^1.3.1 + simple-concat: ^1.0.0 + checksum: 80195e70bf171486e75c31e28e5485468195cc42f85940f8b45c4a68472160144d223eb4d07bc82ef80cb974b7c401db021a540deb2d34ac4b3b8883da2d6401 + languageName: node + linkType: hard + +"simple-swizzle@npm:^0.2.2": + version: 0.2.2 + resolution: "simple-swizzle@npm:0.2.2" + dependencies: + is-arrayish: ^0.3.1 + checksum: a7f3f2ab5c76c4472d5c578df892e857323e452d9f392e1b5cf74b74db66e6294a1e1b8b390b519fa1b96b5b613f2a37db6cffef52c3f1f8f3c5ea64eb2d54c0 + languageName: node + linkType: hard + +"simulate-event@npm:~1.4.0": + version: 1.4.0 + resolution: "simulate-event@npm:1.4.0" + dependencies: + xtend: ^4.0.1 + checksum: d2cbb62f7a0c22aa1964e4df7a01b717c3c437df40dde70112fc06046cb8c7a03ca582571754653abc7c8c06df43d28c57b4f0bdf7a587094e4d6282357eb506 + languageName: node + linkType: hard + +"sirv@npm:^1.0.7": + version: 1.0.19 + resolution: "sirv@npm:1.0.19" + dependencies: + "@polka/url": ^1.0.0-next.20 + mrmime: ^1.0.0 + totalist: ^1.0.0 + checksum: c943cfc61baf85f05f125451796212ec35d4377af4da90ae8ec1fa23e6d7b0b4d9c74a8fbf65af83c94e669e88a09dc6451ba99154235eead4393c10dda5b07c + languageName: node + linkType: hard + +"sisteransi@npm:^1.0.5": + version: 1.0.5 + resolution: "sisteransi@npm:1.0.5" + checksum: aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 + languageName: node + linkType: hard + +"slash@npm:3.0.0, slash@npm:^3.0.0": + version: 3.0.0 + resolution: "slash@npm:3.0.0" + checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c + languageName: node + linkType: hard + +"slash@npm:^4.0.0": + version: 4.0.0 + resolution: "slash@npm:4.0.0" + checksum: da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d + languageName: node + linkType: hard + +"slice-ansi@npm:^4.0.0": + version: 4.0.0 + resolution: "slice-ansi@npm:4.0.0" + dependencies: + ansi-styles: ^4.0.0 + astral-regex: ^2.0.0 + is-fullwidth-code-point: ^3.0.0 + checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^7.0.0": + version: 7.0.0 + resolution: "socks-proxy-agent@npm:7.0.0" + dependencies: + agent-base: ^6.0.2 + debug: ^4.3.3 + socks: ^2.6.2 + checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 + languageName: node + linkType: hard + +"socks@npm:^2.6.2": + version: 2.7.1 + resolution: "socks@npm:2.7.1" + dependencies: + ip: ^2.0.0 + smart-buffer: ^4.2.0 + checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 + languageName: node + linkType: hard + +"sonic-boom@npm:3.3.0": + version: 3.3.0 + resolution: "sonic-boom@npm:3.3.0" + dependencies: + atomic-sleep: ^1.0.0 + checksum: 4a290dd0f3edf49894bb72c631ee304dc3f9be0752c43d516808a365f341821f5cf49997c80ee7c0e67167e0e5131dc71afe7c58812858eb965d6b9746c0cac7 + languageName: node + linkType: hard + +"sonic-boom@npm:^2.2.1": + version: 2.8.0 + resolution: "sonic-boom@npm:2.8.0" + dependencies: + atomic-sleep: ^1.0.0 + checksum: c7f9c89f931d7f60f8e0741551a729f0d81e6dc407a99420fc847a9a4c25af048a615b1188ab3c4f1fb3708fe4904973ddab6ebcc8ed5b78b50ab81a99045910 + languageName: node + linkType: hard + +"sort-keys@npm:^2.0.0": + version: 2.0.0 + resolution: "sort-keys@npm:2.0.0" + dependencies: + is-plain-obj: ^1.0.0 + checksum: f0fd827fa9f8f866e98588d2a38c35209afbf1e9a05bb0e4ceeeb8bbf31d923c8902b0a7e0f561590ddb65e58eba6a74f74b991c85360bcc52e83a3f0d1cffd7 + languageName: node + linkType: hard + +"sort-object-keys@npm:^1.1.3": + version: 1.1.3 + resolution: "sort-object-keys@npm:1.1.3" + checksum: abea944d6722a1710a1aa6e4f9509da085d93d5fc0db23947cb411eedc7731f80022ce8fa68ed83a53dd2ac7441fcf72a3f38c09b3d9bbc4ff80546aa2e151ad + languageName: node + linkType: hard + +"sort-package-json@npm:~1.53.1": + version: 1.53.1 + resolution: "sort-package-json@npm:1.53.1" + dependencies: + detect-indent: ^6.0.0 + detect-newline: 3.1.0 + git-hooks-list: 1.0.3 + globby: 10.0.0 + is-plain-obj: 2.1.0 + sort-object-keys: ^1.1.3 + bin: + sort-package-json: cli.js + checksum: 3bf0b1a625566eb061d7d811f4d8b1cebc2c4d85dcb746fa2b27d39703d3d78edead1aa990273b02264af0a618aa6e7edbf24621e280f03bb06418cbd1f07889 + languageName: node + linkType: hard + +"source-list-map@npm:^2.0.0": + version: 2.0.1 + resolution: "source-list-map@npm:2.0.1" + checksum: 806efc6f75e7cd31e4815e7a3aaf75a45c704871ea4075cb2eb49882c6fca28998f44fc5ac91adb6de03b2882ee6fb02f951fdc85e6a22b338c32bfe19557938 + languageName: node + linkType: hard + +"source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2": + version: 1.0.2 + resolution: "source-map-js@npm:1.0.2" + checksum: c049a7fc4deb9a7e9b481ae3d424cc793cb4845daa690bc5a05d428bf41bf231ced49b4cf0c9e77f9d42fdb3d20d6187619fc586605f5eabe995a316da8d377c + languageName: node + linkType: hard + +"source-map-loader@npm:~1.0.2": + version: 1.0.2 + resolution: "source-map-loader@npm:1.0.2" + dependencies: + data-urls: ^2.0.0 + iconv-lite: ^0.6.2 + loader-utils: ^2.0.0 + schema-utils: ^2.7.0 + source-map: ^0.6.1 + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: 0360b536e904f8fea452d0e122b9199661765229dc62a4b8093cc9d14e985f2ddd146355ede6d11acdd0b9bf4639b364e2526afcf9d3218ed45af63aa5eb053f + languageName: node + linkType: hard + +"source-map-support@npm:0.5.13": + version: 0.5.13 + resolution: "source-map-support@npm:0.5.13" + dependencies: + buffer-from: ^1.0.0 + source-map: ^0.6.0 + checksum: 933550047b6c1a2328599a21d8b7666507427c0f5ef5eaadd56b5da0fd9505e239053c66fe181bf1df469a3b7af9d775778eee283cbb7ae16b902ddc09e93a97 + languageName: node + linkType: hard + +"source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.20": + version: 0.5.21 + resolution: "source-map-support@npm:0.5.21" + dependencies: + buffer-from: ^1.0.0 + source-map: ^0.6.0 + checksum: 43e98d700d79af1d36f859bdb7318e601dfc918c7ba2e98456118ebc4c4872b327773e5a1df09b0524e9e5063bb18f0934538eace60cca2710d1fa687645d137 + languageName: node + linkType: hard + +"source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0, source-map@npm:~0.6.1": + version: 0.6.1 + resolution: "source-map@npm:0.6.1" + checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 + languageName: node + linkType: hard + +"spdx-correct@npm:^3.0.0": + version: 3.2.0 + resolution: "spdx-correct@npm:3.2.0" + dependencies: + spdx-expression-parse: ^3.0.0 + spdx-license-ids: ^3.0.0 + checksum: e9ae98d22f69c88e7aff5b8778dc01c361ef635580e82d29e5c60a6533cc8f4d820803e67d7432581af0cc4fb49973125076ee3b90df191d153e223c004193b2 + languageName: node + linkType: hard + +"spdx-exceptions@npm:^2.1.0": + version: 2.3.0 + resolution: "spdx-exceptions@npm:2.3.0" + checksum: cb69a26fa3b46305637123cd37c85f75610e8c477b6476fa7354eb67c08128d159f1d36715f19be6f9daf4b680337deb8c65acdcae7f2608ba51931540687ac0 + languageName: node + linkType: hard + +"spdx-expression-parse@npm:^3.0.0": + version: 3.0.1 + resolution: "spdx-expression-parse@npm:3.0.1" + dependencies: + spdx-exceptions: ^2.1.0 + spdx-license-ids: ^3.0.0 + checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde + languageName: node + linkType: hard + +"spdx-license-ids@npm:^3.0.0": + version: 3.0.12 + resolution: "spdx-license-ids@npm:3.0.12" + checksum: 92a4dddce62ce1db6fe54a7a839cf85e06abc308fc83b776a55b44e4f1906f02e7ebd506120847039e976bbbad359ea8bdfafb7925eae5cd7e73255f02e0b7d6 + languageName: node + linkType: hard + +"speech-rule-engine@npm:^4.0.6": + version: 4.0.7 + resolution: "speech-rule-engine@npm:4.0.7" + dependencies: + commander: 9.2.0 + wicked-good-xpath: 1.3.0 + xmldom-sre: 0.1.31 + bin: + sre: bin/sre + checksum: e5b8a5878be61d0344d5e9e0327e6bdf25a23de8fb66bd1898719d52b5f12f42b7e11a3387b8f293420c5eaab57b3ed9099be0adcc2132177301e81134612f38 + languageName: node + linkType: hard + +"split2@npm:^3.2.2": + version: 3.2.2 + resolution: "split2@npm:3.2.2" + dependencies: + readable-stream: ^3.0.0 + checksum: 8127ddbedd0faf31f232c0e9192fede469913aa8982aa380752e0463b2e31c2359ef6962eb2d24c125bac59eeec76873678d723b1c7ff696216a1cd071e3994a + languageName: node + linkType: hard + +"split2@npm:^4.0.0": + version: 4.1.0 + resolution: "split2@npm:4.1.0" + checksum: ec581597cb74c13cdfb5e2047543dd40cb1e8e9803c7b1e0c29ede05f2b4f049b2d6e7f2788a225d544549375719658b8f38e9366364dec35dc7a12edfda5ee5 + languageName: node + linkType: hard + +"split@npm:^1.0.1": + version: 1.0.1 + resolution: "split@npm:1.0.1" + dependencies: + through: 2 + checksum: 12f4554a5792c7e98bb3e22b53c63bfa5ef89aa704353e1db608a55b51f5b12afaad6e4a8ecf7843c15f273f43cdadd67b3705cc43d48a75c2cf4641d51f7e7a + languageName: node + linkType: hard + +"sprintf-js@npm:~1.0.2": + version: 1.0.3 + resolution: "sprintf-js@npm:1.0.3" + checksum: 19d79aec211f09b99ec3099b5b2ae2f6e9cdefe50bc91ac4c69144b6d3928a640bb6ae5b3def70c2e85a2c3d9f5ec2719921e3a59d3ca3ef4b2fd1a4656a0df3 + languageName: node + linkType: hard + +"sshpk@npm:^1.7.0": + version: 1.17.0 + resolution: "sshpk@npm:1.17.0" + 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 + checksum: ba109f65c8e6c35133b8e6ed5576abeff8aa8d614824b7275ec3ca308f081fef483607c28d97780c1e235818b0f93ed8c8b56d0a5968d5a23fd6af57718c7597 + languageName: node + linkType: hard + +"ssri@npm:^10.0.0, ssri@npm:^10.0.1": + version: 10.0.4 + resolution: "ssri@npm:10.0.4" + dependencies: + minipass: ^5.0.0 + checksum: fb14da9f8a72b04eab163eb13a9dda11d5962cd2317f85457c4e0b575e9a6e0e3a6a87b5bf122c75cb36565830cd5f263fb457571bf6f1587eb5f95d095d6165 + languageName: node + linkType: hard + +"ssri@npm:^9.0.0, ssri@npm:^9.0.1": + version: 9.0.1 + resolution: "ssri@npm:9.0.1" + dependencies: + minipass: ^3.1.1 + checksum: fb58f5e46b6923ae67b87ad5ef1c5ab6d427a17db0bead84570c2df3cd50b4ceb880ebdba2d60726588272890bae842a744e1ecce5bd2a2a582fccd5068309eb + languageName: node + linkType: hard + +"stack-utils@npm:^2.0.3": + version: 2.0.6 + resolution: "stack-utils@npm:2.0.6" + dependencies: + escape-string-regexp: ^2.0.0 + checksum: 052bf4d25bbf5f78e06c1d5e67de2e088b06871fa04107ca8d3f0e9d9263326e2942c8bedee3545795fc77d787d443a538345eef74db2f8e35db3558c6f91ff7 + languageName: node + linkType: hard + +"statuses@npm:2.0.1": + version: 2.0.1 + resolution: "statuses@npm:2.0.1" + checksum: 18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb + languageName: node + linkType: hard + +"stdin@npm:0.0.1": + version: 0.0.1 + resolution: "stdin@npm:0.0.1" + checksum: c991b430f68027c73456b5518e37585e4b3645cdd8185213bfa598a5b925463929cf0e1a125c78738fe285a52f515fd05f8c965ece9b5aeab5e86a3e3f7128f7 + languageName: node + linkType: hard + +"steno@npm:^0.4.1": + version: 0.4.4 + resolution: "steno@npm:0.4.4" + dependencies: + graceful-fs: ^4.1.3 + checksum: 87df4121cf8159fceb3dc925111aff1e237bdea2d37f6684eabbcdea63bfcff79b3234f2a61ffe8de5cf17fcb97e2cf09075a2a98993251f79e2868fe0d5ba1e + languageName: node + linkType: hard + +"stream-buffers@npm:^3.0.2": + version: 3.0.2 + resolution: "stream-buffers@npm:3.0.2" + checksum: b09fdeea606e3113ebd0e07010ed0cf038608fa396130add9e45deaff5cc3ba845dc25c31ad24f8341f85907846344cb7c85f75ea52c6572e2ac646e9b6072d0 + languageName: node + linkType: hard + +"stream-shift@npm:^1.0.0": + version: 1.0.1 + resolution: "stream-shift@npm:1.0.1" + checksum: 59b82b44b29ec3699b5519a49b3cedcc6db58c72fb40c04e005525dfdcab1c75c4e0c180b923c380f204bed78211b9bad8faecc7b93dece4d004c3f6ec75737b + languageName: node + linkType: hard + +"stream-to-array@npm:~2.3.0": + version: 2.3.0 + resolution: "stream-to-array@npm:2.3.0" + dependencies: + any-promise: ^1.1.0 + checksum: 7feaf63b38399b850615e6ffcaa951e96e4c8f46745dbce4b553a94c5dc43966933813747014935a3ff97793e7f30a65270bde19f82b2932871a1879229a77cf + languageName: node + linkType: hard + +"stream-to-promise@npm:^2.2.0": + version: 2.2.0 + resolution: "stream-to-promise@npm:2.2.0" + dependencies: + any-promise: ~1.3.0 + end-of-stream: ~1.1.0 + stream-to-array: ~2.3.0 + checksum: 2c9ddb69c34d10ad27eb06197abc93fd1b1cd5f9597ead28ade4d6c57f4110d948a2ef14530f2f7b3b967f74f3554b57c38a4501b72a13b27fc8745bd7190d1d + languageName: node + linkType: hard + +"string-length@npm:^4.0.1": + version: 4.0.2 + resolution: "string-length@npm:4.0.2" + dependencies: + char-regex: ^1.0.2 + strip-ansi: ^6.0.0 + checksum: ce85533ef5113fcb7e522bcf9e62cb33871aa99b3729cec5595f4447f660b0cefd542ca6df4150c97a677d58b0cb727a3fe09ac1de94071d05526c73579bf505 + languageName: node + linkType: hard + +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: ^8.0.0 + is-fullwidth-code-point: ^3.0.0 + strip-ansi: ^6.0.1 + checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb + languageName: node + linkType: hard + +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: ^0.2.0 + emoji-regex: ^9.2.2 + strip-ansi: ^7.0.1 + checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 + languageName: node + linkType: hard + +"string.prototype.matchall@npm:^4.0.8": + version: 4.0.8 + resolution: "string.prototype.matchall@npm:4.0.8" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + get-intrinsic: ^1.1.3 + has-symbols: ^1.0.3 + internal-slot: ^1.0.3 + regexp.prototype.flags: ^1.4.3 + side-channel: ^1.0.4 + checksum: 952da3a818de42ad1c10b576140a5e05b4de7b34b8d9dbf00c3ac8c1293e9c0f533613a39c5cda53e0a8221f2e710bc2150e730b1c2278d60004a8a35726efb6 + languageName: node + linkType: hard + +"string.prototype.trimend@npm:^1.0.6": + version: 1.0.6 + resolution: "string.prototype.trimend@npm:1.0.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 0fdc34645a639bd35179b5a08227a353b88dc089adf438f46be8a7c197fc3f22f8514c1c9be4629b3cd29c281582730a8cbbad6466c60f76b5f99cf2addb132e + languageName: node + linkType: hard + +"string.prototype.trimstart@npm:^1.0.6": + version: 1.0.6 + resolution: "string.prototype.trimstart@npm:1.0.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 89080feef416621e6ef1279588994305477a7a91648d9436490d56010a1f7adc39167cddac7ce0b9884b8cdbef086987c4dcb2960209f2af8bac0d23ceff4f41 + languageName: node + linkType: hard + +"string_decoder@npm:^1.1.1, string_decoder@npm:~1.1.1": + version: 1.1.1 + resolution: "string_decoder@npm:1.1.1" + dependencies: + safe-buffer: ~5.1.0 + checksum: 9ab7e56f9d60a28f2be697419917c50cac19f3e8e6c28ef26ed5f4852289fe0de5d6997d29becf59028556f2c62983790c1d9ba1e2a3cc401768ca12d5183a5b + languageName: node + linkType: hard + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: ^5.0.1 + checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c + languageName: node + linkType: hard + +"strip-ansi@npm:^7.0.1": + version: 7.0.1 + resolution: "strip-ansi@npm:7.0.1" + dependencies: + ansi-regex: ^6.0.1 + checksum: 257f78fa433520e7f9897722731d78599cb3fce29ff26a20a5e12ba4957463b50a01136f37c43707f4951817a75e90820174853d6ccc240997adc5df8f966039 + languageName: node + linkType: hard + +"strip-bom@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-bom@npm:3.0.0" + checksum: 8d50ff27b7ebe5ecc78f1fe1e00fcdff7af014e73cf724b46fb81ef889eeb1015fc5184b64e81a2efe002180f3ba431bdd77e300da5c6685d702780fbf0c8d5b + languageName: node + linkType: hard + +"strip-bom@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-bom@npm:4.0.0" + checksum: 9dbcfbaf503c57c06af15fe2c8176fb1bf3af5ff65003851a102749f875a6dbe0ab3b30115eccf6e805e9d756830d3e40ec508b62b3f1ddf3761a20ebe29d3f3 + languageName: node + linkType: hard + +"strip-final-newline@npm:^2.0.0": + version: 2.0.0 + resolution: "strip-final-newline@npm:2.0.0" + checksum: 69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 + languageName: node + linkType: hard + +"strip-final-newline@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-final-newline@npm:3.0.0" + checksum: 23ee263adfa2070cd0f23d1ac14e2ed2f000c9b44229aec9c799f1367ec001478469560abefd00c5c99ee6f0b31c137d53ec6029c53e9f32a93804e18c201050 + languageName: node + linkType: hard + +"strip-indent@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-indent@npm:3.0.0" + dependencies: + min-indent: ^1.0.0 + checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 + languageName: node + linkType: hard + +"strip-indent@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-indent@npm:4.0.0" + dependencies: + min-indent: ^1.0.1 + checksum: 06cbcd93da721c46bc13caeb1c00af93a9b18146a1c95927672d2decab6a25ad83662772417cea9317a2507fb143253ecc23c4415b64f5828cef9b638a744598 + languageName: node + linkType: hard + +"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 + languageName: node + linkType: hard + +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 1074ccb63270d32ca28edfb0a281c96b94dc679077828135141f27d52a5a398ef5e78bcf22809d23cadc2b81dfbe345eb5fd8699b385c8b1128907dec4a7d1e1 + languageName: node + linkType: hard + +"strong-log-transformer@npm:2.1.0, strong-log-transformer@npm:^2.1.0": + version: 2.1.0 + resolution: "strong-log-transformer@npm:2.1.0" + dependencies: + duplexer: ^0.1.1 + minimist: ^1.2.0 + through: ^2.3.4 + bin: + sl-log-transformer: bin/sl-log-transformer.js + checksum: abf9a4ac143118f26c3a0771b204b02f5cf4fa80384ae158f25e02bfbff761038accc44a7f65869ccd5a5995a7f2c16b1466b83149644ba6cecd3072a8927297 + languageName: node + linkType: hard + +"style-loader@npm:~3.3.1": + version: 3.3.1 + resolution: "style-loader@npm:3.3.1" + peerDependencies: + webpack: ^5.0.0 + checksum: 470feef680f59e2fce4d6601b5c55b88c01ad8d1dd693c528ffd591ff5fd7c01a4eff3bdbe62f26f847d6bd2430c9ab594be23307cfe7a3446ab236683f0d066 + languageName: node + linkType: hard + +"style-mod@npm:^4.0.0": + version: 4.0.0 + resolution: "style-mod@npm:4.0.0" + checksum: c19f73d660a94244f0715180a6141bf75d05e5b156cc956ba11970b83cd303c3f7edafe5fb61a3192da6186cc008bdcdd803a979070f9b64e13046463644043c + languageName: node + linkType: hard + +"style-search@npm:^0.1.0": + version: 0.1.0 + resolution: "style-search@npm:0.1.0" + checksum: 3cfefe335033aad6d47da0725cb48f5db91a73935954c77eab77d9e415e6668cdb406da4a4f7ef9f1aca77853cf5ba7952c45e869caa5bd6439691d88098d468 + languageName: node + linkType: hard + +"stylelint-config-prettier@npm:^9.0.3": + version: 9.0.5 + resolution: "stylelint-config-prettier@npm:9.0.5" + peerDependencies: + stylelint: ">= 11.x < 15" + bin: + stylelint-config-prettier: bin/check.js + stylelint-config-prettier-check: bin/check.js + checksum: 3d04e463e0bb7e42a5ddec49eea6ef4ea07705d887e8a3ff1fcb82278a5e2bec1a36b8498ea7ed2d24878de29d7c94ac75b1d3ac4f8b19c3a84970595b29261f + languageName: node + linkType: hard + +"stylelint-config-recommended@npm:^13.0.0": + version: 13.0.0 + resolution: "stylelint-config-recommended@npm:13.0.0" + peerDependencies: + stylelint: ^15.10.0 + checksum: a56eb6d1a7c7f3a7a172b54bc34218859ba22a5a06816fb4d0964f66cb83cf372062f2c97830e994ad68243548e15fc49abf28887c3261ab1b471b3aa69f8e82 + languageName: node + linkType: hard + +"stylelint-config-standard@npm:^34.0.0": + version: 34.0.0 + resolution: "stylelint-config-standard@npm:34.0.0" + dependencies: + stylelint-config-recommended: ^13.0.0 + peerDependencies: + stylelint: ^15.10.0 + checksum: 536249800c04b48a9c354067765f042713982e8222be17bb897a27d26546e50adfb87e6f1e4541807d720de3554345da99ab470e13e8d7ab0ab326c73ae3df61 + languageName: node + linkType: hard + +"stylelint-csstree-validator@npm:^3.0.0": + version: 3.0.0 + resolution: "stylelint-csstree-validator@npm:3.0.0" + dependencies: + css-tree: ^2.3.1 + peerDependencies: + stylelint: ">=7.0.0 <16.0.0" + checksum: e518c8c17714022946b7637c23a6816fd2ccdd6052a19c5a138b3f7ce9b913ead9c612ac4401e102f14800a19967dbfd4b588b44cbf3f3c6a5984bef7bda4017 + languageName: node + linkType: hard + +"stylelint-prettier@npm:^4.0.0": + version: 4.0.0 + resolution: "stylelint-prettier@npm:4.0.0" + dependencies: + prettier-linter-helpers: ^1.0.0 + peerDependencies: + prettier: ">=3.0.0" + stylelint: ">=15.8.0" + checksum: 3e7cff833e30b1eab9ae6e82f1b0a3596fd3dd214489d71d37b0899e677ae9d50cc74c4c1bbb3b1275903f03c1401b2ca6f8c1cf2631108363d3e7845d7b6300 + languageName: node + linkType: hard + +"stylelint@npm:^15.10.1": + version: 15.10.1 + resolution: "stylelint@npm:15.10.1" + dependencies: + "@csstools/css-parser-algorithms": ^2.3.0 + "@csstools/css-tokenizer": ^2.1.1 + "@csstools/media-query-list-parser": ^2.1.2 + "@csstools/selector-specificity": ^3.0.0 + balanced-match: ^2.0.0 + colord: ^2.9.3 + cosmiconfig: ^8.2.0 + css-functions-list: ^3.1.0 + css-tree: ^2.3.1 + debug: ^4.3.4 + fast-glob: ^3.3.0 + fastest-levenshtein: ^1.0.16 + file-entry-cache: ^6.0.1 + global-modules: ^2.0.0 + globby: ^11.1.0 + globjoin: ^0.1.4 + html-tags: ^3.3.1 + ignore: ^5.2.4 + import-lazy: ^4.0.0 + imurmurhash: ^0.1.4 + is-plain-object: ^5.0.0 + known-css-properties: ^0.27.0 + mathml-tag-names: ^2.1.3 + meow: ^10.1.5 + micromatch: ^4.0.5 + normalize-path: ^3.0.0 + picocolors: ^1.0.0 + postcss: ^8.4.24 + postcss-resolve-nested-selector: ^0.1.1 + postcss-safe-parser: ^6.0.0 + postcss-selector-parser: ^6.0.13 + postcss-value-parser: ^4.2.0 + resolve-from: ^5.0.0 + string-width: ^4.2.3 + strip-ansi: ^6.0.1 + style-search: ^0.1.0 + supports-hyperlinks: ^3.0.0 + svg-tags: ^1.0.0 + table: ^6.8.1 + write-file-atomic: ^5.0.1 + bin: + stylelint: bin/stylelint.mjs + checksum: 8eeae81fe4ed2dfc580d7c401806dbb058c14631abfafd0821db32f1e649aee62e3d39dda3462c6122826df91bd9799409be926e91b55b007622f51e44eb94c1 + languageName: node + linkType: hard + +"supports-color@npm:^5.3.0": + version: 5.5.0 + resolution: "supports-color@npm:5.5.0" + dependencies: + has-flag: ^3.0.0 + checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac + languageName: node + linkType: hard + +"supports-color@npm:^7.0.0, supports-color@npm:^7.1.0, supports-color@npm:^7.2.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: ^4.0.0 + checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a + languageName: node + linkType: hard + +"supports-color@npm:^8.0.0": + version: 8.1.1 + resolution: "supports-color@npm:8.1.1" + dependencies: + has-flag: ^4.0.0 + checksum: c052193a7e43c6cdc741eb7f378df605636e01ad434badf7324f17fb60c69a880d8d8fcdcb562cf94c2350e57b937d7425ab5b8326c67c2adc48f7c87c1db406 + languageName: node + linkType: hard + +"supports-hyperlinks@npm:^3.0.0": + version: 3.0.0 + resolution: "supports-hyperlinks@npm:3.0.0" + dependencies: + has-flag: ^4.0.0 + supports-color: ^7.0.0 + checksum: 41021305de5255b10d821bf93c7a781f783e1693d0faec293d7fc7ccf17011b90bde84b0295fa92ba75c6c390351fe84fdd18848cad4bf656e464a958243c3e7 + languageName: node + linkType: hard + +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae + languageName: node + linkType: hard + +"svg-tags@npm:^1.0.0": + version: 1.0.0 + resolution: "svg-tags@npm:1.0.0" + checksum: 407e5ef87cfa2fb81c61d738081c2decd022ce13b922d035b214b49810630bf5d1409255a4beb3a940b77b32f6957806deff16f1bf0ce1ab11c7a184115a0b7f + languageName: node + linkType: hard + +"svgo@npm:^3.0.1": + version: 3.0.2 + resolution: "svgo@npm:3.0.2" + dependencies: + "@trysound/sax": 0.2.0 + commander: ^7.2.0 + css-select: ^5.1.0 + css-tree: ^2.2.1 + csso: ^5.0.5 + picocolors: ^1.0.0 + bin: + svgo: bin/svgo + checksum: 381ba14aa782e71ab7033227634a3041c11fa3e2769aeaf0df43a08a615de61925108e34f55af6e7c5146f4a3109e78deabb4fa9d687e36d45d1f848b4e23d17 + languageName: node + linkType: hard + +"symbol-tree@npm:^3.2.4": + version: 3.2.4 + resolution: "symbol-tree@npm:3.2.4" + checksum: 6e8fc7e1486b8b54bea91199d9535bb72f10842e40c79e882fc94fb7b14b89866adf2fd79efa5ebb5b658bc07fb459ccce5ac0e99ef3d72f474e74aaf284029d + languageName: node + linkType: hard + +"synckit@npm:^0.8.5": + version: 0.8.5 + resolution: "synckit@npm:0.8.5" + dependencies: + "@pkgr/utils": ^2.3.1 + tslib: ^2.5.0 + checksum: 8a9560e5d8f3d94dc3cf5f7b9c83490ffa30d320093560a37b88f59483040771fd1750e76b9939abfbb1b5a23fd6dfbae77f6b338abffe7cae7329cd9b9bb86b + languageName: node + linkType: hard + +"systeminformation@npm:^5.8.6": + version: 5.17.12 + resolution: "systeminformation@npm:5.17.12" + bin: + systeminformation: lib/cli.js + checksum: 0f005bb0a00eaa08ee2d04afc7fde688440e2fc85f09cf247b74dac0f5d08fdd24cad0c233733f1eb69721085efc5beb425afe814e5fa9f5d1aaa4cbe523e5cc + conditions: (os=darwin | os=linux | os=win32 | os=freebsd | os=openbsd | os=netbsd | os=sunos | os=android) + languageName: node + linkType: hard + +"table@npm:^6.8.1": + version: 6.8.1 + resolution: "table@npm:6.8.1" + dependencies: + ajv: ^8.0.1 + lodash.truncate: ^4.4.2 + slice-ansi: ^4.0.0 + string-width: ^4.2.3 + strip-ansi: ^6.0.1 + checksum: 08249c7046125d9d0a944a6e96cfe9ec66908d6b8a9db125531be6eb05fa0de047fd5542e9d43b4f987057f00a093b276b8d3e19af162a9c40db2681058fd306 + languageName: node + linkType: hard + +"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0": + version: 2.2.1 + resolution: "tapable@npm:2.2.1" + checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51 + languageName: node + linkType: hard + +"tar-stream@npm:~2.2.0": + version: 2.2.0 + resolution: "tar-stream@npm:2.2.0" + 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 + checksum: 699831a8b97666ef50021c767f84924cfee21c142c2eb0e79c63254e140e6408d6d55a065a2992548e72b06de39237ef2b802b99e3ece93ca3904a37622a66f3 + languageName: node + linkType: hard + +"tar@npm:6.1.11, tar@npm:^6.0.5, tar@npm:^6.1.11, tar@npm:^6.1.2": + version: 6.1.11 + resolution: "tar@npm:6.1.11" + dependencies: + chownr: ^2.0.0 + fs-minipass: ^2.0.0 + minipass: ^3.0.0 + minizlib: ^2.1.1 + mkdirp: ^1.0.3 + yallist: ^4.0.0 + checksum: a04c07bb9e2d8f46776517d4618f2406fb977a74d914ad98b264fc3db0fe8224da5bec11e5f8902c5b9bcb8ace22d95fbe3c7b36b8593b7dfc8391a25898f32f + languageName: node + linkType: hard + +"temp-dir@npm:1.0.0": + version: 1.0.0 + resolution: "temp-dir@npm:1.0.0" + checksum: cb2b58ddfb12efa83e939091386ad73b425c9a8487ea0095fe4653192a40d49184a771a1beba99045fbd011e389fd563122d79f54f82be86a55620667e08a6b2 + languageName: node + linkType: hard + +"terser-webpack-plugin@npm:^5.1.3, terser-webpack-plugin@npm:^5.3.7": + version: 5.3.7 + resolution: "terser-webpack-plugin@npm:5.3.7" + dependencies: + "@jridgewell/trace-mapping": ^0.3.17 + jest-worker: ^27.4.5 + schema-utils: ^3.1.1 + serialize-javascript: ^6.0.1 + terser: ^5.16.5 + peerDependencies: + webpack: ^5.1.0 + peerDependenciesMeta: + "@swc/core": + optional: true + esbuild: + optional: true + uglify-js: + optional: true + checksum: 095e699fdeeb553cdf2c6f75f983949271b396d9c201d7ae9fc633c45c1c1ad14c7257ef9d51ccc62213dd3e97f875870ba31550f6d4f1b6674f2615562da7f7 + languageName: node + linkType: hard + +"terser@npm:^4.6.3": + version: 4.8.1 + resolution: "terser@npm:4.8.1" + dependencies: + commander: ^2.20.0 + source-map: ~0.6.1 + source-map-support: ~0.5.12 + bin: + terser: bin/terser + checksum: b342819bf7e82283059aaa3f22bb74deb1862d07573ba5a8947882190ad525fd9b44a15074986be083fd379c58b9a879457a330b66dcdb77b485c44267f9a55a + languageName: node + linkType: hard + +"terser@npm:^5.10.0, terser@npm:^5.16.5": + version: 5.16.6 + resolution: "terser@npm:5.16.6" + dependencies: + "@jridgewell/source-map": ^0.3.2 + acorn: ^8.5.0 + commander: ^2.20.0 + source-map-support: ~0.5.20 + bin: + terser: bin/terser + checksum: f763a7bcc7b98cb2bfc41434f7b92bfe8a701a12c92ea6049377736c8e6de328240d654a20dfe15ce170fd783491b9873fad9f4cd8fee4f6c6fb8ca407859dee + languageName: node + linkType: hard + +"test-exclude@npm:^6.0.0": + version: 6.0.0 + resolution: "test-exclude@npm:6.0.0" + dependencies: + "@istanbuljs/schema": ^0.1.2 + glob: ^7.1.4 + minimatch: ^3.0.4 + checksum: 3b34a3d77165a2cb82b34014b3aba93b1c4637a5011807557dc2f3da826c59975a5ccad765721c4648b39817e3472789f9b0fa98fc854c5c1c7a1e632aacdc28 + languageName: node + linkType: hard + +"text-extensions@npm:^1.0.0": + version: 1.9.0 + resolution: "text-extensions@npm:1.9.0" + checksum: 56a9962c1b62d39b2bcb369b7558ca85c1b55e554b38dfd725edcc0a1babe5815782a60c17ff6b839093b163dfebb92b804208aaaea616ec7571c8059ae0cf44 + languageName: node + linkType: hard + +"text-table@npm:^0.2.0": + version: 0.2.0 + resolution: "text-table@npm:0.2.0" + checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a + languageName: node + linkType: hard + +"thenify-all@npm:^1.0.0": + version: 1.6.0 + resolution: "thenify-all@npm:1.6.0" + dependencies: + thenify: ">= 3.1.0 < 4" + checksum: dba7cc8a23a154cdcb6acb7f51d61511c37a6b077ec5ab5da6e8b874272015937788402fd271fdfc5f187f8cb0948e38d0a42dcc89d554d731652ab458f5343e + languageName: node + linkType: hard + +"thenify@npm:>= 3.1.0 < 4": + version: 3.3.1 + resolution: "thenify@npm:3.3.1" + dependencies: + any-promise: ^1.0.0 + checksum: 84e1b804bfec49f3531215f17b4a6e50fd4397b5f7c1bccc427b9c656e1ecfb13ea79d899930184f78bc2f57285c54d9a50a590c8868f4f0cef5c1d9f898b05e + languageName: node + linkType: hard + +"thread-stream@npm:^0.15.1": + version: 0.15.2 + resolution: "thread-stream@npm:0.15.2" + dependencies: + real-require: ^0.1.0 + checksum: 0547795a8f357ba1ac0dba29c71f965182e29e21752951a04a7167515ee37524bfba6c410f31e65a01a8d3e5b93400b812889aa09523e38ce4d744c894ffa6c0 + languageName: node + linkType: hard + +"through2@npm:^2.0.0": + version: 2.0.5 + resolution: "through2@npm:2.0.5" + dependencies: + readable-stream: ~2.3.6 + xtend: ~4.0.1 + checksum: beb0f338aa2931e5660ec7bf3ad949e6d2e068c31f4737b9525e5201b824ac40cac6a337224856b56bd1ddd866334bbfb92a9f57cd6f66bc3f18d3d86fc0fe50 + languageName: node + linkType: hard + +"through@npm:2, through@npm:>=2.2.7 <3, through@npm:^2.3.4, through@npm:^2.3.6": + version: 2.3.8 + resolution: "through@npm:2.3.8" + checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd + languageName: node + linkType: hard + +"timers-ext@npm:^0.1.5, timers-ext@npm:^0.1.7": + version: 0.1.7 + resolution: "timers-ext@npm:0.1.7" + dependencies: + es5-ext: ~0.10.46 + next-tick: 1 + checksum: ef3f27a0702a88d885bcbb0317c3e3ecd094ce644da52e7f7d362394a125d9e3578292a8f8966071a980d8abbc3395725333b1856f3ae93835b46589f700d938 + languageName: node + linkType: hard + +"tinylogic@npm:^1.0.3": + version: 1.0.3 + resolution: "tinylogic@npm:1.0.3" + dependencies: + chevrotain: ^9.1.0 + checksum: fdf7fcc170050889b210fd035b1eb2ac81a68d1324010a427eeee53ac49613ecaa3fbd33b41adb1264dfb02b4d500b3f442da1db3ffc53834c654345c1658afa + languageName: node + linkType: hard + +"titleize@npm:^3.0.0": + version: 3.0.0 + resolution: "titleize@npm:3.0.0" + checksum: 71fbbeabbfb36ccd840559f67f21e356e1d03da2915b32d2ae1a60ddcc13a124be2739f696d2feb884983441d159a18649e8d956648d591bdad35c430a6b6d28 + languageName: node + linkType: hard + +"tmp@npm:^0.0.33": + version: 0.0.33 + resolution: "tmp@npm:0.0.33" + dependencies: + os-tmpdir: ~1.0.2 + checksum: 902d7aceb74453ea02abbf58c203f4a8fc1cead89b60b31e354f74ed5b3fb09ea817f94fb310f884a5d16987dd9fa5a735412a7c2dd088dd3d415aa819ae3a28 + languageName: node + linkType: hard + +"tmp@npm:~0.2.1": + version: 0.2.1 + resolution: "tmp@npm:0.2.1" + dependencies: + rimraf: ^3.0.0 + checksum: 8b1214654182575124498c87ca986ac53dc76ff36e8f0e0b67139a8d221eaecfdec108c0e6ec54d76f49f1f72ab9325500b246f562b926f85bcdfca8bf35df9e + languageName: node + linkType: hard + +"tmpl@npm:1.0.5": + version: 1.0.5 + resolution: "tmpl@npm:1.0.5" + checksum: cd922d9b853c00fe414c5a774817be65b058d54a2d01ebb415840960406c669a0fc632f66df885e24cb022ec812739199ccbdb8d1164c3e513f85bfca5ab2873 + languageName: node + linkType: hard + +"to-fast-properties@npm:^2.0.0": + version: 2.0.0 + resolution: "to-fast-properties@npm:2.0.0" + checksum: be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: ^7.0.0 + checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed + languageName: node + linkType: hard + +"toidentifier@npm:1.0.1": + version: 1.0.1 + resolution: "toidentifier@npm:1.0.1" + checksum: 952c29e2a85d7123239b5cfdd889a0dde47ab0497f0913d70588f19c53f7e0b5327c95f4651e413c74b785147f9637b17410ac8c846d5d4a20a5a33eb6dc3a45 + languageName: node + linkType: hard + +"topojson-client@npm:^3.1.0": + version: 3.1.0 + resolution: "topojson-client@npm:3.1.0" + dependencies: + commander: 2 + bin: + topo2geo: bin/topo2geo + topomerge: bin/topomerge + topoquantize: bin/topoquantize + checksum: 8c029a4f18324ace0b8b55dd90edbd40c9e3c6de18bafbb5da37ca20ebf20e26fbd4420891acb3c2c264e214185f7557871f5651a9eee517028663be98d836de + languageName: node + linkType: hard + +"toposort@npm:^2.0.2": + version: 2.0.2 + resolution: "toposort@npm:2.0.2" + checksum: d64c74b570391c9432873f48e231b439ee56bc49f7cb9780b505cfdf5cb832f808d0bae072515d93834dd6bceca5bb34448b5b4b408335e4d4716eaf68195dcb + languageName: node + linkType: hard + +"totalist@npm:^1.0.0": + version: 1.1.0 + resolution: "totalist@npm:1.1.0" + checksum: dfab80c7104a1d170adc8c18782d6c04b7df08352dec452191208c66395f7ef2af7537ddfa2cf1decbdcfab1a47afbbf0dec6543ea191da98c1c6e1599f86adc + languageName: node + linkType: hard + +"tough-cookie@npm:^4.1.2": + version: 4.1.2 + resolution: "tough-cookie@npm:4.1.2" + dependencies: + psl: ^1.1.33 + punycode: ^2.1.1 + universalify: ^0.2.0 + url-parse: ^1.5.3 + checksum: a7359e9a3e875121a84d6ba40cc184dec5784af84f67f3a56d1d2ae39b87c0e004e6ba7c7331f9622a7d2c88609032473488b28fe9f59a1fec115674589de39a + languageName: node + linkType: hard + +"tough-cookie@npm:~2.5.0": + version: 2.5.0 + resolution: "tough-cookie@npm:2.5.0" + dependencies: + psl: ^1.1.28 + punycode: ^2.1.1 + checksum: 16a8cd090224dd176eee23837cbe7573ca0fa297d7e468ab5e1c02d49a4e9a97bb05fef11320605eac516f91d54c57838a25864e8680e27b069a5231d8264977 + languageName: node + linkType: hard + +"tr46@npm:^2.1.0": + version: 2.1.0 + resolution: "tr46@npm:2.1.0" + dependencies: + punycode: ^2.1.1 + checksum: ffe6049b9dca3ae329b059aada7f515b0f0064c611b39b51ff6b53897e954650f6f63d9319c6c008d36ead477c7b55e5f64c9dc60588ddc91ff720d64eb710b3 + languageName: node + linkType: hard + +"tr46@npm:^3.0.0": + version: 3.0.0 + resolution: "tr46@npm:3.0.0" + dependencies: + punycode: ^2.1.1 + checksum: 44c3cc6767fb800490e6e9fd64fd49041aa4e49e1f6a012b34a75de739cc9ed3a6405296072c1df8b6389ae139c5e7c6496f659cfe13a04a4bff3a1422981270 + languageName: node + linkType: hard + +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 + languageName: node + linkType: hard + +"treeify@npm:^1.1.0": + version: 1.1.0 + resolution: "treeify@npm:1.1.0" + checksum: aa00dded220c1dd052573bd6fc2c52862f09870851a284f0d3650d72bf913ba9b4f6b824f4f1ab81899bae29375f4266b07fe47cbf82343a1efa13cc09ce87af + languageName: node + linkType: hard + +"trim-newlines@npm:^3.0.0": + version: 3.0.1 + resolution: "trim-newlines@npm:3.0.1" + checksum: b530f3fadf78e570cf3c761fb74fef655beff6b0f84b29209bac6c9622db75ad1417f4a7b5d54c96605dcd72734ad44526fef9f396807b90839449eb543c6206 + languageName: node + linkType: hard + +"trim-newlines@npm:^4.0.2": + version: 4.1.1 + resolution: "trim-newlines@npm:4.1.1" + checksum: 5b09f8e329e8f33c1111ef26906332ba7ba7248cde3e26fc054bb3d69f2858bf5feedca9559c572ff91f33e52977c28e0d41c387df6a02a633cbb8c2d8238627 + languageName: node + linkType: hard + +"ts-jest@npm:^29.1.0": + version: 29.1.0 + resolution: "ts-jest@npm:29.1.0" + dependencies: + bs-logger: 0.x + fast-json-stable-stringify: 2.x + jest-util: ^29.0.0 + json5: ^2.2.3 + lodash.memoize: 4.x + make-error: 1.x + semver: 7.x + yargs-parser: ^21.0.1 + peerDependencies: + "@babel/core": ">=7.0.0-beta.0 <8" + "@jest/types": ^29.0.0 + babel-jest: ^29.0.0 + jest: ^29.0.0 + typescript: ">=4.3 <6" + peerDependenciesMeta: + "@babel/core": + optional: true + "@jest/types": + optional: true + babel-jest: + optional: true + esbuild: + optional: true + bin: + ts-jest: cli.js + checksum: 535dc42ad523cbe1e387701fb2e448518419b515c082f09b25411f0b3dd0b854cf3e8141c316d6f4b99883aeb4a4f94159cbb1edfb06d7f77ea6229fadb2e1bf + languageName: node + linkType: hard + +"tsconfig-paths@npm:^4.1.2": + version: 4.1.2 + resolution: "tsconfig-paths@npm:4.1.2" + dependencies: + json5: ^2.2.2 + minimist: ^1.2.6 + strip-bom: ^3.0.0 + checksum: 3d9151ecea139594e25618717de15769ab9f38f8e6d510ac16e592b23e7f7105ea13cec5694c3de7e132c98277b775e18edd1651964164ee6d75737c408494cc + languageName: node + linkType: hard + +"tslib@npm:^1.13.0, tslib@npm:^1.8.1": + version: 1.14.1 + resolution: "tslib@npm:1.14.1" + checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd + languageName: node + linkType: hard + +"tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0": + version: 2.6.0 + resolution: "tslib@npm:2.6.0" + checksum: c01066038f950016a18106ddeca4649b4d76caa76ec5a31e2a26e10586a59fceb4ee45e96719bf6c715648e7c14085a81fee5c62f7e9ebee68e77a5396e5538f + languageName: node + linkType: hard + +"tslib@npm:~2.5.0": + version: 2.5.0 + resolution: "tslib@npm:2.5.0" + checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1 + languageName: node + linkType: hard + +"tsscmp@npm:1.0.6": + version: 1.0.6 + resolution: "tsscmp@npm:1.0.6" + checksum: 1512384def36bccc9125cabbd4c3b0e68608d7ee08127ceaa0b84a71797263f1a01c7f82fa69be8a3bd3c1396e2965d2f7b52d581d3a5eeaf3967fbc52e3b3bf + languageName: node + linkType: hard + +"tsutils@npm:^3.21.0": + version: 3.21.0 + resolution: "tsutils@npm:3.21.0" + dependencies: + tslib: ^1.8.1 + peerDependencies: + typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48 + languageName: node + linkType: hard + +"tuf-js@npm:^1.1.3": + version: 1.1.7 + resolution: "tuf-js@npm:1.1.7" + dependencies: + "@tufjs/models": 1.0.4 + debug: ^4.3.4 + make-fetch-happen: ^11.1.1 + checksum: 089fc0dabe1fcaeca8b955b358b34272f23237ac9e074b5f983349eb44d9688fd137f28f493bbd8dfd865d1af4e76e0cc869d307eadd054d1b404914c3124ae5 + languageName: node + linkType: hard + +"tunnel-agent@npm:^0.6.0": + version: 0.6.0 + resolution: "tunnel-agent@npm:0.6.0" + dependencies: + safe-buffer: ^5.0.1 + checksum: 05f6510358f8afc62a057b8b692f05d70c1782b70db86d6a1e0d5e28a32389e52fa6e7707b6c5ecccacc031462e4bc35af85ecfe4bbc341767917b7cf6965711 + languageName: node + linkType: hard + +"tunnel@npm:^0.0.6": + version: 0.0.6 + resolution: "tunnel@npm:0.0.6" + checksum: c362948df9ad34b649b5585e54ce2838fa583aa3037091aaed66793c65b423a264e5229f0d7e9a95513a795ac2bd4cb72cda7e89a74313f182c1e9ae0b0994fa + languageName: node + linkType: hard + +"tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": + version: 0.14.5 + resolution: "tweetnacl@npm:0.14.5" + checksum: 6061daba1724f59473d99a7bb82e13f211cdf6e31315510ae9656fefd4779851cb927adad90f3b488c8ed77c106adc0421ea8055f6f976ff21b27c5c4e918487 + languageName: node + linkType: hard + +"typanion@npm:^3.3.1, typanion@npm:^3.8.0": + version: 3.14.0 + resolution: "typanion@npm:3.14.0" + checksum: fc0590d02c13c659eb1689e8adf7777e6c00dc911377e44cd36fe1b1271cfaca71547149f12cdc275058c0de5562a14e5273adbae66d47e6e0320e36007f5912 + languageName: node + linkType: hard + +"type-check@npm:^0.4.0, type-check@npm:~0.4.0": + version: 0.4.0 + resolution: "type-check@npm:0.4.0" + dependencies: + prelude-ls: ^1.2.1 + checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a + languageName: node + linkType: hard + +"type-check@npm:~0.3.2": + version: 0.3.2 + resolution: "type-check@npm:0.3.2" + dependencies: + prelude-ls: ~1.1.2 + checksum: dd3b1495642731bc0e1fc40abe5e977e0263005551ac83342ecb6f4f89551d106b368ec32ad3fb2da19b3bd7b2d1f64330da2ea9176d8ddbfe389fb286eb5124 + languageName: node + linkType: hard + +"type-detect@npm:4.0.8": + version: 4.0.8 + resolution: "type-detect@npm:4.0.8" + checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15 + languageName: node + linkType: hard + +"type-fest@npm:^0.18.0": + version: 0.18.1 + resolution: "type-fest@npm:0.18.1" + checksum: e96dcee18abe50ec82dab6cbc4751b3a82046da54c52e3b2d035b3c519732c0b3dd7a2fa9df24efd1a38d953d8d4813c50985f215f1957ee5e4f26b0fe0da395 + languageName: node + linkType: hard + +"type-fest@npm:^0.20.2": + version: 0.20.2 + resolution: "type-fest@npm:0.20.2" + checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73 + languageName: node + linkType: hard + +"type-fest@npm:^0.21.3": + version: 0.21.3 + resolution: "type-fest@npm:0.21.3" + checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 + languageName: node + linkType: hard + +"type-fest@npm:^0.4.1": + version: 0.4.1 + resolution: "type-fest@npm:0.4.1" + checksum: 25f882d9cc2f24af7a0a529157f96dead157894c456bfbad16d48f990c43b470dfb79848e8d9c03fe1be72a7d169e44f6f3135b54628393c66a6189c5dc077f7 + languageName: node + linkType: hard + +"type-fest@npm:^0.6.0": + version: 0.6.0 + resolution: "type-fest@npm:0.6.0" + checksum: b2188e6e4b21557f6e92960ec496d28a51d68658018cba8b597bd3ef757721d1db309f120ae987abeeda874511d14b776157ff809f23c6d1ce8f83b9b2b7d60f + languageName: node + linkType: hard + +"type-fest@npm:^0.8.1": + version: 0.8.1 + resolution: "type-fest@npm:0.8.1" + checksum: d61c4b2eba24009033ae4500d7d818a94fd6d1b481a8111612ee141400d5f1db46f199c014766b9fa9b31a6a7374d96fc748c6d688a78a3ce5a33123839becb7 + languageName: node + linkType: hard + +"type-fest@npm:^1.0.1, type-fest@npm:^1.2.1, type-fest@npm:^1.2.2": + version: 1.4.0 + resolution: "type-fest@npm:1.4.0" + checksum: b011c3388665b097ae6a109a437a04d6f61d81b7357f74cbcb02246f2f5bd72b888ae33631b99871388122ba0a87f4ff1c94078e7119ff22c70e52c0ff828201 + languageName: node + linkType: hard + +"type-fest@npm:^3.0.0": + version: 3.6.1 + resolution: "type-fest@npm:3.6.1" + checksum: f7e39bf6b74a883661ec8642707f49c33cfcdc6221e1ba36b1d329c1cf301d87351b3ca0839b894cbfe47dc62140c0ce47e69c88f76800b678e0b67b7fe826e6 + languageName: node + linkType: hard + +"type-is@npm:~1.6.18": + version: 1.6.18 + resolution: "type-is@npm:1.6.18" + dependencies: + media-typer: 0.3.0 + mime-types: ~2.1.24 + checksum: 2c8e47675d55f8b4e404bcf529abdf5036c537a04c2b20177bcf78c9e3c1da69da3942b1346e6edb09e823228c0ee656ef0e033765ec39a70d496ef601a0c657 + languageName: node + linkType: hard + +"type@npm:^1.0.1": + version: 1.2.0 + resolution: "type@npm:1.2.0" + checksum: dae8c64f82c648b985caf321e9dd6e8b7f4f2e2d4f846fc6fd2c8e9dc7769382d8a52369ddbaccd59aeeceb0df7f52fb339c465be5f2e543e81e810e413451ee + languageName: node + linkType: hard + +"type@npm:^2.7.2": + version: 2.7.2 + resolution: "type@npm:2.7.2" + checksum: 0f42379a8adb67fe529add238a3e3d16699d95b42d01adfe7b9a7c5da297f5c1ba93de39265ba30ffeb37dfd0afb3fb66ae09f58d6515da442219c086219f6f4 + languageName: node + linkType: hard + +"typed-array-length@npm:^1.0.4": + version: 1.0.4 + resolution: "typed-array-length@npm:1.0.4" + dependencies: + call-bind: ^1.0.2 + for-each: ^0.3.3 + is-typed-array: ^1.1.9 + checksum: 2228febc93c7feff142b8c96a58d4a0d7623ecde6c7a24b2b98eb3170e99f7c7eff8c114f9b283085cd59dcd2bd43aadf20e25bba4b034a53c5bb292f71f8956 + languageName: node + linkType: hard + +"typedarray@npm:^0.0.6": + version: 0.0.6 + resolution: "typedarray@npm:0.0.6" + checksum: 33b39f3d0e8463985eeaeeacc3cb2e28bc3dfaf2a5ed219628c0b629d5d7b810b0eb2165f9f607c34871d5daa92ba1dc69f49051cf7d578b4cbd26c340b9d1b1 + languageName: node + linkType: hard + +"typedoc-plugin-mdn-links@npm:^3.0.3": + version: 3.0.3 + resolution: "typedoc-plugin-mdn-links@npm:3.0.3" + peerDependencies: + typedoc: ">= 0.23.14 || 0.24.x" + checksum: 1682f8a65e1eff892f5ae0424919007d0673d9abda7c7f401b294fc73d64ce8fc4e1cbb35e5389170a8c48ed57efe6ee81403f870499c62decb016b689fa6522 + languageName: node + linkType: hard + +"typedoc@npm:~0.24.7": + version: 0.24.7 + resolution: "typedoc@npm:0.24.7" + dependencies: + lunr: ^2.3.9 + marked: ^4.3.0 + minimatch: ^9.0.0 + shiki: ^0.14.1 + peerDependencies: + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x + bin: + typedoc: bin/typedoc + checksum: 9ae433566cb02b96deb9eb2a9f5b23d1b199f5aeb61ca8c7e2653ff5d339fbfb4d526e024febab4f3278332978814aaa0885f1d5925ba21a441d93a611510ac3 + languageName: node + linkType: hard + +"typescript@npm:>=3 < 6, typescript@npm:~5.0.4": + version: 5.0.4 + resolution: "typescript@npm:5.0.4" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 82b94da3f4604a8946da585f7d6c3025fff8410779e5bde2855ab130d05e4fd08938b9e593b6ebed165bda6ad9292b230984f10952cf82f0a0ca07bbeaa08172 + languageName: node + linkType: hard + +"typescript@patch:typescript@>=3 < 6#~builtin, typescript@patch:typescript@~5.0.4#~builtin": + version: 5.0.4 + resolution: "typescript@patch:typescript@npm%3A5.0.4#~builtin::version=5.0.4&hash=85af82" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: bb309d320c59a26565fb3793dba550576ab861018ff3fd1b7fccabbe46ae4a35546bc45f342c0a0b6f265c801ccdf64ffd68f548f117ceb7f0eac4b805cd52a9 + languageName: node + linkType: hard + +"typestyle@npm:^2.0.4": + version: 2.4.0 + resolution: "typestyle@npm:2.4.0" + dependencies: + csstype: 3.0.10 + free-style: 3.1.0 + checksum: 8b4f02c24f67b594f98507b15a753dabd4db5eb0af007e1d310527c64030e11e9464b25b5a6bc65fb5eec9a4459a8336050121ecc29063ac87b8b47a6d698893 + languageName: node + linkType: hard + +"uglify-js@npm:^3.1.4": + version: 3.17.4 + resolution: "uglify-js@npm:3.17.4" + bin: + uglifyjs: bin/uglifyjs + checksum: 7b3897df38b6fc7d7d9f4dcd658599d81aa2b1fb0d074829dd4e5290f7318dbca1f4af2f45acb833b95b1fe0ed4698662ab61b87e94328eb4c0a0d3435baf924 + languageName: node + linkType: hard + +"unbox-primitive@npm:^1.0.2": + version: 1.0.2 + resolution: "unbox-primitive@npm:1.0.2" + dependencies: + call-bind: ^1.0.2 + has-bigints: ^1.0.2 + has-symbols: ^1.0.3 + which-boxed-primitive: ^1.0.2 + checksum: b7a1cf5862b5e4b5deb091672ffa579aa274f648410009c81cca63fed3b62b610c4f3b773f912ce545bb4e31edc3138975b5bc777fc6e4817dca51affb6380e9 + languageName: node + linkType: hard + +"unicode-canonical-property-names-ecmascript@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" + checksum: 39be078afd014c14dcd957a7a46a60061bc37c4508ba146517f85f60361acf4c7539552645ece25de840e17e293baa5556268d091ca6762747fdd0c705001a45 + languageName: node + linkType: hard + +"unicode-match-property-ecmascript@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-match-property-ecmascript@npm:2.0.0" + dependencies: + unicode-canonical-property-names-ecmascript: ^2.0.0 + unicode-property-aliases-ecmascript: ^2.0.0 + checksum: 1f34a7434a23df4885b5890ac36c5b2161a809887000be560f56ad4b11126d433c0c1c39baf1016bdabed4ec54829a6190ee37aa24919aa116dc1a5a8a62965a + languageName: node + linkType: hard + +"unicode-match-property-value-ecmascript@npm:^2.1.0": + version: 2.1.0 + resolution: "unicode-match-property-value-ecmascript@npm:2.1.0" + checksum: 8d6f5f586b9ce1ed0e84a37df6b42fdba1317a05b5df0c249962bd5da89528771e2d149837cad11aa26bcb84c35355cb9f58a10c3d41fa3b899181ece6c85220 + languageName: node + linkType: hard + +"unicode-property-aliases-ecmascript@npm:^2.0.0": + version: 2.1.0 + resolution: "unicode-property-aliases-ecmascript@npm:2.1.0" + checksum: 243524431893649b62cc674d877bd64ef292d6071dd2fd01ab4d5ad26efbc104ffcd064f93f8a06b7e4ec54c172bf03f6417921a0d8c3a9994161fe1f88f815b + languageName: node + linkType: hard + +"unique-filename@npm:^2.0.0": + version: 2.0.1 + resolution: "unique-filename@npm:2.0.1" + dependencies: + unique-slug: ^3.0.0 + checksum: 807acf3381aff319086b64dc7125a9a37c09c44af7620bd4f7f3247fcd5565660ac12d8b80534dcbfd067e6fe88a67e621386dd796a8af828d1337a8420a255f + languageName: node + linkType: hard + +"unique-filename@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-filename@npm:3.0.0" + dependencies: + unique-slug: ^4.0.0 + checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df + languageName: node + linkType: hard + +"unique-slug@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-slug@npm:3.0.0" + dependencies: + imurmurhash: ^0.1.4 + checksum: 49f8d915ba7f0101801b922062ee46b7953256c93ceca74303bd8e6413ae10aa7e8216556b54dc5382895e8221d04f1efaf75f945c2e4a515b4139f77aa6640c + languageName: node + linkType: hard + +"unique-slug@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: ^0.1.4 + checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 + languageName: node + linkType: hard + +"universal-user-agent@npm:^6.0.0": + version: 6.0.0 + resolution: "universal-user-agent@npm:6.0.0" + checksum: 5092bbc80dd0d583cef0b62c17df0043193b74f425112ea6c1f69bc5eda21eeec7a08d8c4f793a277eb2202ffe9b44bec852fa3faff971234cd209874d1b79ef + languageName: node + linkType: hard + +"universalify@npm:^0.2.0": + version: 0.2.0 + resolution: "universalify@npm:0.2.0" + checksum: e86134cb12919d177c2353196a4cc09981524ee87abf621f7bc8d249dbbbebaec5e7d1314b96061497981350df786e4c5128dbf442eba104d6e765bc260678b5 + languageName: node + linkType: hard + +"universalify@npm:^2.0.0": + version: 2.0.0 + resolution: "universalify@npm:2.0.0" + checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 + languageName: node + linkType: hard + +"unix-crypt-td-js@npm:1.1.4": + version: 1.1.4 + resolution: "unix-crypt-td-js@npm:1.1.4" + checksum: c1bfcd699fa0fa15eac087760e34fdf7e2e686de1c40dde7f550c2429389fd7ef68bf83ce804ce7882551573330832aae32e80be3ce991f7080aabd98f8bd554 + languageName: node + linkType: hard + +"unpipe@npm:1.0.0, unpipe@npm:~1.0.0": + version: 1.0.0 + resolution: "unpipe@npm:1.0.0" + checksum: 4fa18d8d8d977c55cb09715385c203197105e10a6d220087ec819f50cb68870f02942244f1017565484237f1f8c5d3cd413631b1ae104d3096f24fdfde1b4aa2 + languageName: node + linkType: hard + +"untildify@npm:^4.0.0": + version: 4.0.0 + resolution: "untildify@npm:4.0.0" + checksum: 39ced9c418a74f73f0a56e1ba4634b4d959422dff61f4c72a8e39f60b99380c1b45ed776fbaa0a4101b157e4310d873ad7d114e8534ca02609b4916bb4187fb9 + languageName: node + linkType: hard + +"upath@npm:2.0.1": + version: 2.0.1 + resolution: "upath@npm:2.0.1" + checksum: 2db04f24a03ef72204c7b969d6991abec9e2cb06fb4c13a1fd1c59bc33b46526b16c3325e55930a11ff86a77a8cbbcda8f6399bf914087028c5beae21ecdb33c + languageName: node + linkType: hard + +"update-browserslist-db@npm:^1.0.10": + version: 1.0.10 + resolution: "update-browserslist-db@npm:1.0.10" + dependencies: + escalade: ^3.1.1 + picocolors: ^1.0.0 + peerDependencies: + browserslist: ">= 4.21.0" + bin: + browserslist-lint: cli.js + checksum: 12db73b4f63029ac407b153732e7cd69a1ea8206c9100b482b7d12859cd3cd0bc59c602d7ae31e652706189f1acb90d42c53ab24a5ba563ed13aebdddc5561a0 + languageName: node + linkType: hard + +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" + dependencies: + punycode: ^2.1.0 + checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633 + languageName: node + linkType: hard + +"url-parse@npm:^1.5.3, url-parse@npm:~1.5.4": + version: 1.5.10 + resolution: "url-parse@npm:1.5.10" + dependencies: + querystringify: ^2.1.1 + requires-port: ^1.0.0 + checksum: fbdba6b1d83336aca2216bbdc38ba658d9cfb8fc7f665eb8b17852de638ff7d1a162c198a8e4ed66001ddbf6c9888d41e4798912c62b4fd777a31657989f7bdf + languageName: node + linkType: hard + +"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 + languageName: node + linkType: hard + +"util@npm:^0.10.3": + version: 0.10.4 + resolution: "util@npm:0.10.4" + dependencies: + inherits: 2.0.3 + checksum: 913f9a90d05a60e91f91af01b8bd37e06bca4cc02d7b49e01089f9d5b78be2fffd61fb1a41b517de7238c5fc7337fa939c62d1fb4eb82e014894c7bee6637aaf + languageName: node + linkType: hard + +"utila@npm:~0.4": + version: 0.4.0 + resolution: "utila@npm:0.4.0" + checksum: 97ffd3bd2bb80c773429d3fb8396469115cd190dded1e733f190d8b602bd0a1bcd6216b7ce3c4395ee3c79e3c879c19d268dbaae3093564cb169ad1212d436f4 + languageName: node + linkType: hard + +"utils-merge@npm:1.0.1": + version: 1.0.1 + resolution: "utils-merge@npm:1.0.1" + checksum: c81095493225ecfc28add49c106ca4f09cdf56bc66731aa8dabc2edbbccb1e1bfe2de6a115e5c6a380d3ea166d1636410b62ef216bb07b3feb1cfde1d95d5080 + languageName: node + linkType: hard + +"uuid@npm:^3.3.2": + version: 3.4.0 + resolution: "uuid@npm:3.4.0" + bin: + uuid: ./bin/uuid + checksum: 58de2feed61c59060b40f8203c0e4ed7fd6f99d42534a499f1741218a1dd0c129f4aa1de797bcf822c8ea5da7e4137aa3673431a96dae729047f7aca7b27866f + languageName: node + linkType: hard + +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + languageName: node + linkType: hard + +"uuid@npm:^9.0.0": + version: 9.0.0 + resolution: "uuid@npm:9.0.0" + bin: + uuid: dist/bin/uuid + checksum: 8dd2c83c43ddc7e1c71e36b60aea40030a6505139af6bee0f382ebcd1a56f6cd3028f7f06ffb07f8cf6ced320b76aea275284b224b002b289f89fe89c389b028 + languageName: node + linkType: hard + +"v8-compile-cache@npm:2.3.0": + version: 2.3.0 + resolution: "v8-compile-cache@npm:2.3.0" + checksum: adb0a271eaa2297f2f4c536acbfee872d0dd26ec2d76f66921aa7fc437319132773483344207bdbeee169225f4739016d8d2dbf0553913a52bb34da6d0334f8e + languageName: node + linkType: hard + +"v8-to-istanbul@npm:^9.0.1": + version: 9.1.0 + resolution: "v8-to-istanbul@npm:9.1.0" + dependencies: + "@jridgewell/trace-mapping": ^0.3.12 + "@types/istanbul-lib-coverage": ^2.0.1 + convert-source-map: ^1.6.0 + checksum: 2069d59ee46cf8d83b4adfd8a5c1a90834caffa9f675e4360f1157ffc8578ef0f763c8f32d128334424159bb6b01f3876acd39cd13297b2769405a9da241f8d1 + languageName: node + linkType: hard + +"validate-npm-package-license@npm:3.0.4, validate-npm-package-license@npm:^3.0.1, validate-npm-package-license@npm:^3.0.4": + version: 3.0.4 + resolution: "validate-npm-package-license@npm:3.0.4" + dependencies: + spdx-correct: ^3.0.0 + spdx-expression-parse: ^3.0.0 + checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad + languageName: node + linkType: hard + +"validate-npm-package-name@npm:5.0.0, validate-npm-package-name@npm:^5.0.0": + version: 5.0.0 + resolution: "validate-npm-package-name@npm:5.0.0" + dependencies: + builtins: ^5.0.0 + checksum: 5342a994986199b3c28e53a8452a14b2bb5085727691ea7aa0d284a6606b127c371e0925ae99b3f1ef7cc7d2c9de75f52eb61a3d1cc45e39bca1e3a9444cbb4e + languageName: node + linkType: hard + +"validate-npm-package-name@npm:^3.0.0": + version: 3.0.0 + resolution: "validate-npm-package-name@npm:3.0.0" + dependencies: + builtins: ^1.0.3 + checksum: ce4c68207abfb22c05eedb09ff97adbcedc80304a235a0844f5344f1fd5086aa80e4dbec5684d6094e26e35065277b765c1caef68bcea66b9056761eddb22967 + languageName: node + linkType: hard + +"validate.io-array@npm:^1.0.3": + version: 1.0.6 + resolution: "validate.io-array@npm:1.0.6" + checksum: 54eca83ebc702e3e46499f9d9e77287a95ae25c4e727cd2fafee29c7333b3a36cca0c5d8f090b9406262786de80750fba85e7e7ef41e20bf8cc67d5570de449b + languageName: node + linkType: hard + +"validate.io-function@npm:^1.0.2": + version: 1.0.2 + resolution: "validate.io-function@npm:1.0.2" + checksum: e4cce2479a20cb7c42e8630c777fb107059c27bc32925f769e3a73ca5fd62b4892d897b3c80227e14d5fcd1c5b7d05544e0579d63e59f14034c0052cda7f7c44 + languageName: node + linkType: hard + +"validate.io-integer-array@npm:^1.0.0": + version: 1.0.0 + resolution: "validate.io-integer-array@npm:1.0.0" + dependencies: + validate.io-array: ^1.0.3 + validate.io-integer: ^1.0.4 + checksum: 5f6d7fab8df7d2bf546a05e830201768464605539c75a2c2417b632b4411a00df84b462f81eac75e1be95303e7e0ac92f244c137424739f4e15cd21c2eb52c7f + languageName: node + linkType: hard + +"validate.io-integer@npm:^1.0.4": + version: 1.0.5 + resolution: "validate.io-integer@npm:1.0.5" + dependencies: + validate.io-number: ^1.0.3 + checksum: 88b3f8bb5a5277a95305d64abbfc437079220ce4f57a148cc6113e7ccec03dd86b10a69d413982602aa90a62b8d516148a78716f550dcd3aff863ac1c2a7a5e6 + languageName: node + linkType: hard + +"validate.io-number@npm:^1.0.3": + version: 1.0.3 + resolution: "validate.io-number@npm:1.0.3" + checksum: 42418aeb6c969efa745475154fe576809b02eccd0961aad0421b090d6e7a12d23a3e28b0d5dddd2c6347c1a6bdccb82bba5048c716131cd20207244d50e07282 + languageName: node + linkType: hard + +"validator@npm:13.9.0": + version: 13.9.0 + resolution: "validator@npm:13.9.0" + checksum: e2c936f041f61faa42bafd17c6faddf939498666cd82e88d733621c286893730b008959f4cb12ab3e236148a4f3805c30b85e3dcf5e0efd8b0cbcd36c02bfc0c + languageName: node + linkType: hard + +"vary@npm:^1, vary@npm:~1.1.2": + version: 1.1.2 + resolution: "vary@npm:1.1.2" + checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b + languageName: node + linkType: hard + +"vega-canvas@npm:^1.2.6, vega-canvas@npm:^1.2.7": + version: 1.2.7 + resolution: "vega-canvas@npm:1.2.7" + checksum: 6ff92fcdf0c359f2f662909c859a7f4cb4a502436136ab2f4c02373c47a621996ec0eea23e2108f11d62a618be301de86cd8528b5058c2e207a53ddd7ff58d1b + languageName: node + linkType: hard + +"vega-crossfilter@npm:~4.1.1": + version: 4.1.1 + resolution: "vega-crossfilter@npm:4.1.1" + dependencies: + d3-array: ^3.2.2 + vega-dataflow: ^5.7.5 + vega-util: ^1.17.1 + checksum: e399f7e92d7ba273ad5c1a9e29d362a9ec7feaeacb976eff3aa205b318382fb37a9fac3150ec1cb806364cd2b2cb54d5f23aea3285db684df2b4c27836422464 + languageName: node + linkType: hard + +"vega-dataflow@npm:^5.7.3, vega-dataflow@npm:^5.7.5, vega-dataflow@npm:~5.7.5": + version: 5.7.5 + resolution: "vega-dataflow@npm:5.7.5" + dependencies: + vega-format: ^1.1.1 + vega-loader: ^4.5.1 + vega-util: ^1.17.1 + checksum: 917ed63e88b0871169a883f68da127a404d88e50c9ed6fa3f063a706016b064594fb804a2bf99f09bc4a899819cac320bdde12467edc861af1acc024552dd202 + languageName: node + linkType: hard + +"vega-embed@npm:^6.2.1": + version: 6.21.3 + resolution: "vega-embed@npm:6.21.3" + dependencies: + fast-json-patch: ^3.1.1 + json-stringify-pretty-compact: ^3.0.0 + semver: ^7.3.8 + tslib: ^2.5.0 + vega-interpreter: ^1.0.4 + vega-schema-url-parser: ^2.2.0 + vega-themes: ^2.12.1 + vega-tooltip: ^0.30.1 + yallist: "*" + peerDependencies: + vega: ^5.21.0 + vega-lite: "*" + checksum: e1c40e2111916760dd806cb562b09f5028c2ab941af0469e929d5df436c651a730ebe9aa6fcaed3461196f18c96ff94a5c590adc0a7cb50f33d4c9ef78096417 + languageName: node + linkType: hard + +"vega-encode@npm:~4.9.1": + version: 4.9.1 + resolution: "vega-encode@npm:4.9.1" + dependencies: + d3-array: ^3.2.2 + d3-interpolate: ^3.0.1 + vega-dataflow: ^5.7.5 + vega-scale: ^7.3.0 + vega-util: ^1.17.1 + checksum: 2d95623438832d43f0c9266349e0d9ad5b1eee24477d4561d886fbb62c3f031ea430370633193471fcbffcc8d629e290e07c64dbc975929bf4c721f953408640 + languageName: node + linkType: hard + +"vega-event-selector@npm:^3.0.1, vega-event-selector@npm:~3.0.0, vega-event-selector@npm:~3.0.1": + version: 3.0.1 + resolution: "vega-event-selector@npm:3.0.1" + checksum: 66d09b5800a19a9b0c75f28811b140a1a2e70e84be6d6f87c568cdbce6e17c8e195f130f4e3de5d6dc737142d1f46f4fe7645177e154582cc8ba27c6845b54e8 + languageName: node + linkType: hard + +"vega-expression@npm:^5.0.1, vega-expression@npm:~5.0.0, vega-expression@npm:~5.0.1": + version: 5.0.1 + resolution: "vega-expression@npm:5.0.1" + dependencies: + "@types/estree": ^1.0.0 + vega-util: ^1.17.1 + checksum: 396e950209a98a3fb1e28ba554f179c07aaeac7d11cfac9298a2af0b98456d69ec6573ecc7f21eff6f9f95bbfa8c59a1093d25e8ce586d0c0c589c230784db17 + languageName: node + linkType: hard + +"vega-force@npm:~4.2.0": + version: 4.2.0 + resolution: "vega-force@npm:4.2.0" + dependencies: + d3-force: ^3.0.0 + vega-dataflow: ^5.7.5 + vega-util: ^1.17.1 + checksum: 8a371ca8d0892bc3e932cc279bbf54fe8b88e2b384c42f8df9877c801191953f3ee3e2f516f675a69ecb052ed081232dfb3438989620e8ad5c2a316ccee60277 + languageName: node + linkType: hard + +"vega-format@npm:^1.1.1, vega-format@npm:~1.1.1": + version: 1.1.1 + resolution: "vega-format@npm:1.1.1" + dependencies: + d3-array: ^3.2.2 + d3-format: ^3.1.0 + d3-time-format: ^4.1.0 + vega-time: ^2.1.1 + vega-util: ^1.17.1 + checksum: d506acb8611a6340ff419ebf308a758a54aaf3cf141863553df83980dcf8dc7bf806bee257d11a52d43682d159d7be03ab8a92bdd4d018d8c9f39a70c45cb197 + languageName: node + linkType: hard + +"vega-functions@npm:^5.13.1, vega-functions@npm:~5.13.1": + version: 5.13.1 + resolution: "vega-functions@npm:5.13.1" + dependencies: + d3-array: ^3.2.2 + d3-color: ^3.1.0 + d3-geo: ^3.1.0 + vega-dataflow: ^5.7.5 + vega-expression: ^5.0.1 + vega-scale: ^7.3.0 + vega-scenegraph: ^4.10.2 + vega-selections: ^5.4.1 + vega-statistics: ^1.8.1 + vega-time: ^2.1.1 + vega-util: ^1.17.1 + checksum: 05d154f29dec1742935bfe2852176e392e7c3a107ef76e2c0fe103c7f68812084218ee3c50ef13ba250fa6629d0f4e3a0997fac4b475a1f27be1e465e99b170b + languageName: node + linkType: hard + +"vega-geo@npm:~4.4.1": + version: 4.4.1 + resolution: "vega-geo@npm:4.4.1" + dependencies: + d3-array: ^3.2.2 + d3-color: ^3.1.0 + d3-geo: ^3.1.0 + vega-canvas: ^1.2.7 + vega-dataflow: ^5.7.5 + vega-projection: ^1.6.0 + vega-statistics: ^1.8.1 + vega-util: ^1.17.1 + checksum: e9c62d9134c2449a1a80cd5cb71ed6dc455d893a36fdcb1a696bcae3897670c32687cf14a0f366b0ec76905e5be406131dc671e5d607ffcbef74e94b8c697007 + languageName: node + linkType: hard + +"vega-hierarchy@npm:~4.1.1": + version: 4.1.1 + resolution: "vega-hierarchy@npm:4.1.1" + dependencies: + d3-hierarchy: ^3.1.2 + vega-dataflow: ^5.7.5 + vega-util: ^1.17.1 + checksum: beb23948922f1b52bf03b836d71d3a5a36db3a6bfe2af74b6a5fc45a2e2e877226313e2389772be62a459728467618175d8c02a07e88330844fdec45fd5f69ac + languageName: node + linkType: hard + +"vega-interpreter@npm:^1.0.4": + version: 1.0.5 + resolution: "vega-interpreter@npm:1.0.5" + checksum: ed54bbeddc7942aa442ddf224b620fe68122ef4b93967376a03b6463feddf3da7a837e7b1e0a8d23fbf55898d3ac4a00a034f07acecb05b2d3e09621609dd19e + languageName: node + linkType: hard + +"vega-label@npm:~1.2.1": + version: 1.2.1 + resolution: "vega-label@npm:1.2.1" + dependencies: + vega-canvas: ^1.2.6 + vega-dataflow: ^5.7.3 + vega-scenegraph: ^4.9.2 + vega-util: ^1.15.2 + checksum: 2704c99328ead677441e746acd8f4529301437d08b2758933fc13353d2eab9af353e4ebcc4ff1f09f41d600401b097e2df3c9e8e56d4861e5216222dd9e29185 + languageName: node + linkType: hard + +"vega-lite@npm:^5.6.1, vega-lite@npm:^5.6.1-next.1": + version: 5.6.1 + resolution: "vega-lite@npm:5.6.1" + dependencies: + "@types/clone": ~2.1.1 + clone: ~2.1.2 + fast-deep-equal: ~3.1.3 + fast-json-stable-stringify: ~2.1.0 + json-stringify-pretty-compact: ~3.0.0 + tslib: ~2.5.0 + vega-event-selector: ~3.0.0 + vega-expression: ~5.0.0 + vega-util: ~1.17.0 + yargs: ~17.6.2 + peerDependencies: + vega: ^5.22.0 + bin: + vl2pdf: bin/vl2pdf + vl2png: bin/vl2png + vl2svg: bin/vl2svg + vl2vg: bin/vl2vg + checksum: a06cbd0531cc71a7aeacae3ffde936a80d3cf58ff5942fb89f3544a7b5e0e055f00069dd51950cd09d667f0eefbeb12c7dccb64dd43cbb23b9eff2be1a990979 + languageName: node + linkType: hard + +"vega-loader@npm:^4.5.1, vega-loader@npm:~4.5.1": + version: 4.5.1 + resolution: "vega-loader@npm:4.5.1" + dependencies: + d3-dsv: ^3.0.1 + node-fetch: ^2.6.7 + topojson-client: ^3.1.0 + vega-format: ^1.1.1 + vega-util: ^1.17.1 + checksum: 95f6eebc75a97665cf34faaea431934047e1b2e9d7532f48f62dab4884d606a7d9da53962e1631a5790a7a867f720581852a3db9be1a7f667882062f6c102ee0 + languageName: node + linkType: hard + +"vega-parser@npm:~6.2.0": + version: 6.2.0 + resolution: "vega-parser@npm:6.2.0" + dependencies: + vega-dataflow: ^5.7.5 + vega-event-selector: ^3.0.1 + vega-functions: ^5.13.1 + vega-scale: ^7.3.0 + vega-util: ^1.17.1 + checksum: 19872153c16aab30c4df338e0df7bd331e0bf74c7c6afce5428df555b9bdb0c4acf76b54092cacd4726a1349912ea803c90e1b30d53f4a02044e0559873969a7 + languageName: node + linkType: hard + +"vega-projection@npm:^1.6.0, vega-projection@npm:~1.6.0": + version: 1.6.0 + resolution: "vega-projection@npm:1.6.0" + dependencies: + d3-geo: ^3.1.0 + d3-geo-projection: ^4.0.0 + vega-scale: ^7.3.0 + checksum: 9c52848e294ff68051fe9f44fa536656c4e6be3d474bd3359e21aa154ab282755eaee624ac31b1ca01816227900e1d81a6d191e36f46e47525ed6648397f0fa0 + languageName: node + linkType: hard + +"vega-regression@npm:~1.1.1": + version: 1.1.1 + resolution: "vega-regression@npm:1.1.1" + dependencies: + d3-array: ^3.2.2 + vega-dataflow: ^5.7.3 + vega-statistics: ^1.7.9 + vega-util: ^1.15.2 + checksum: 61686565ad0df517378207acb6b03baba9ee0fb3acef10d5b7cc996509ae322ad1a54a4eb20af9e15468fc3a8adb21d9008d29d1e450663c885c1626702f20f5 + languageName: node + linkType: hard + +"vega-runtime@npm:^6.1.4, vega-runtime@npm:~6.1.4": + version: 6.1.4 + resolution: "vega-runtime@npm:6.1.4" + dependencies: + vega-dataflow: ^5.7.5 + vega-util: ^1.17.1 + checksum: a1da40ddb3109f1ced8e61d2e7b52784fbb29936ee4c47cb5630dbbeb12ef6e0c3cd3cd189c34377f82402bf19c61dd148d90330fec743b8667635ac48e4ba29 + languageName: node + linkType: hard + +"vega-scale@npm:^7.3.0, vega-scale@npm:~7.3.0": + version: 7.3.0 + resolution: "vega-scale@npm:7.3.0" + dependencies: + d3-array: ^3.2.2 + d3-interpolate: ^3.0.1 + d3-scale: ^4.0.2 + vega-time: ^2.1.1 + vega-util: ^1.17.1 + checksum: 8e434f27a51a913dd18374ec0d2bc33758eda7db1ee6342721644f977e705268b8df6b3e89813774d776d03a0cd24f91d4d59f9e80951f67dfbbf8637f5a69ad + languageName: node + linkType: hard + +"vega-scenegraph@npm:^4.10.2, vega-scenegraph@npm:^4.9.2, vega-scenegraph@npm:~4.10.2": + version: 4.10.2 + resolution: "vega-scenegraph@npm:4.10.2" + dependencies: + d3-path: ^3.1.0 + d3-shape: ^3.2.0 + vega-canvas: ^1.2.7 + vega-loader: ^4.5.1 + vega-scale: ^7.3.0 + vega-util: ^1.17.1 + checksum: 6caf3e298297b918c8b6a72f019e51e2bfbaecd316e4d1c37d855ac9366d177cdbf16e9c8857c5ccde128bcd9645af7ee7dc81111bcd743d192e1a3b9a9d7185 + languageName: node + linkType: hard + +"vega-schema-url-parser@npm:^2.2.0": + version: 2.2.0 + resolution: "vega-schema-url-parser@npm:2.2.0" + checksum: 1ab17cde0a2514f42cfd0a1a19c7451e104025c68c09a15c9fe6a0f09bcc7b1c814a8a40f28ab5a69f3c9bda9824ca3f553a7b4338c5c64f7072edcd7bc3d130 + languageName: node + linkType: hard + +"vega-selections@npm:^5.4.1": + version: 5.4.1 + resolution: "vega-selections@npm:5.4.1" + dependencies: + d3-array: 3.2.2 + vega-expression: ^5.0.1 + vega-util: ^1.17.1 + checksum: c594d41ec3886af94976e4dc4e152bea9b3975a22d435aa38dac2aab105851cb83fd4aa0f1e81a47f8bc0bea1677af93816331e3ed084ab3ec2e51b3544c109f + languageName: node + linkType: hard + +"vega-statistics@npm:^1.7.9, vega-statistics@npm:^1.8.1, vega-statistics@npm:~1.8.1": + version: 1.8.1 + resolution: "vega-statistics@npm:1.8.1" + dependencies: + d3-array: ^3.2.2 + checksum: 031f7b617dc8d41f6834b2381ea48a11247630ec6934b0559e4874447072dbbaa5df1eedfd9b8a8959f7bab7d09d3bf828c06c1cd830e1dd9d9234c422b328b6 + languageName: node + linkType: hard + +"vega-themes@npm:^2.12.1": + version: 2.12.1 + resolution: "vega-themes@npm:2.12.1" + peerDependencies: + vega: "*" + vega-lite: "*" + checksum: 2ef22dc8e25c579b27d94d41df0058660a14fbf2d68ce53da08f7e6cc0afdf6cde020b92fddd1a00fbc286e6a95d8d4813a6828c6a9ad8b4a3b5aa000e0db418 + languageName: node + linkType: hard + +"vega-time@npm:^2.1.1, vega-time@npm:~2.1.1": + version: 2.1.1 + resolution: "vega-time@npm:2.1.1" + dependencies: + d3-array: ^3.2.2 + d3-time: ^3.1.0 + vega-util: ^1.17.1 + checksum: 3d6a50f779be4b5e7f27bd2aae766035c29e59e03e62d2e96b94a2f759ed3104c1102c1006dd416e7b819ee501880ae7a722c2fa9aabf9efac86503c1aada14a + languageName: node + linkType: hard + +"vega-tooltip@npm:^0.30.1": + version: 0.30.1 + resolution: "vega-tooltip@npm:0.30.1" + dependencies: + vega-util: ^1.17.0 + checksum: 427dd60459334716af3c7f13ed5dde1b9643d512b68e1e7ef750f6675f1305e48cce3e57469dc83300d7289035dd3f30953dca541dde98063c4f0937fab60acb + languageName: node + linkType: hard + +"vega-transforms@npm:~4.10.1": + version: 4.10.1 + resolution: "vega-transforms@npm:4.10.1" + dependencies: + d3-array: ^3.2.2 + vega-dataflow: ^5.7.5 + vega-statistics: ^1.8.1 + vega-time: ^2.1.1 + vega-util: ^1.17.1 + checksum: fda63a71b53de180c30c43eabd63eab6bb8ab183890077d41d45688db92d1ad7d9951d987b9c5dff5a8cd61d163b75bdb2aa847e0d86aa788025d15ac38e38de + languageName: node + linkType: hard + +"vega-typings@npm:~0.24.0": + version: 0.24.0 + resolution: "vega-typings@npm:0.24.0" + dependencies: + "@types/geojson": ^7946.0.10 + vega-event-selector: ^3.0.1 + vega-expression: ^5.0.1 + vega-util: ^1.17.1 + checksum: 430dc0a95d0d07f00e82829d1c3a81efdf6512476ed53bc263bf98f1c0e1bdb780d0125609360d386af287a79467c21069d9f14f5eec12999602f937799c6b5c + languageName: node + linkType: hard + +"vega-util@npm:^1.15.2, vega-util@npm:^1.17.0, vega-util@npm:^1.17.1, vega-util@npm:~1.17.0, vega-util@npm:~1.17.1": + version: 1.17.1 + resolution: "vega-util@npm:1.17.1" + checksum: aa8b6a43bd38f49aea6d97988cdc2bdae6e0adb59080287b87dc82b9b7246faa87a20d2c143e700ba5669adaa249dd27b88b3c74c4b4df9fa6a510381c575713 + languageName: node + linkType: hard + +"vega-view-transforms@npm:~4.5.9": + version: 4.5.9 + resolution: "vega-view-transforms@npm:4.5.9" + dependencies: + vega-dataflow: ^5.7.5 + vega-scenegraph: ^4.10.2 + vega-util: ^1.17.1 + checksum: aeeaf3c2f1a02b1303c16a586dbcb20f208c101d06d7e988e18ab71fb67d87be5d8ff228ebf25971535d6e41dc816168cfa68b8676e7250df07a40aefdea32a7 + languageName: node + linkType: hard + +"vega-view@npm:~5.11.1": + version: 5.11.1 + resolution: "vega-view@npm:5.11.1" + dependencies: + d3-array: ^3.2.2 + d3-timer: ^3.0.1 + vega-dataflow: ^5.7.5 + vega-format: ^1.1.1 + vega-functions: ^5.13.1 + vega-runtime: ^6.1.4 + vega-scenegraph: ^4.10.2 + vega-util: ^1.17.1 + checksum: 82ddc74593b3a359d0b3458bc06573673ff9bf13f84020cb36fb4676c5d7f547e9650eb6faaa76799fbcedd27bcd266603dbd08c420e2d2229cc6b9f48a4a66d + languageName: node + linkType: hard + +"vega-voronoi@npm:~4.2.1": + version: 4.2.1 + resolution: "vega-voronoi@npm:4.2.1" + dependencies: + d3-delaunay: ^6.0.2 + vega-dataflow: ^5.7.5 + vega-util: ^1.17.1 + checksum: f618174ad5f451c507a80e373288bb2c0da7a8a908d62f885bc77b354c4334504ae2d1042742f68ad419ade7b548aeca9ca1042ae5541bebd7f5297afc23bb35 + languageName: node + linkType: hard + +"vega-wordcloud@npm:~4.1.4": + version: 4.1.4 + resolution: "vega-wordcloud@npm:4.1.4" + dependencies: + vega-canvas: ^1.2.7 + vega-dataflow: ^5.7.5 + vega-scale: ^7.3.0 + vega-statistics: ^1.8.1 + vega-util: ^1.17.1 + checksum: 34d1882651d3a2f34ce40a6eaeed700de126f627cdf041ec2bcc7ada46d7b4b68a38a2974236eec87ee876d9abd095af7ab17e7698b0e2fbc831460767969d7a + languageName: node + linkType: hard + +"vega@npm:^5.20.0": + version: 5.24.0 + resolution: "vega@npm:5.24.0" + dependencies: + vega-crossfilter: ~4.1.1 + vega-dataflow: ~5.7.5 + vega-encode: ~4.9.1 + vega-event-selector: ~3.0.1 + vega-expression: ~5.0.1 + vega-force: ~4.2.0 + vega-format: ~1.1.1 + vega-functions: ~5.13.1 + vega-geo: ~4.4.1 + vega-hierarchy: ~4.1.1 + vega-label: ~1.2.1 + vega-loader: ~4.5.1 + vega-parser: ~6.2.0 + vega-projection: ~1.6.0 + vega-regression: ~1.1.1 + vega-runtime: ~6.1.4 + vega-scale: ~7.3.0 + vega-scenegraph: ~4.10.2 + vega-statistics: ~1.8.1 + vega-time: ~2.1.1 + vega-transforms: ~4.10.1 + vega-typings: ~0.24.0 + vega-util: ~1.17.1 + vega-view: ~5.11.1 + vega-view-transforms: ~4.5.9 + vega-voronoi: ~4.2.1 + vega-wordcloud: ~4.1.4 + checksum: 974ef09d56cb768a6f31dae80856e9c5a22cc2dbe79d73ded95b3743539f7d9981759cc9e214f939489d632faf9b69bad079a4d5bc53439c685e809b14d7a7a1 + languageName: node + linkType: hard + +"verdaccio-audit@npm:11.0.0-6-next.34": + version: 11.0.0-6-next.34 + resolution: "verdaccio-audit@npm:11.0.0-6-next.34" + dependencies: + "@verdaccio/config": 6.0.0-6-next.71 + "@verdaccio/core": 6.0.0-6-next.71 + express: 4.18.2 + https-proxy-agent: 5.0.1 + node-fetch: cjs + checksum: 1f1ba70999268941068a96f915d41a888828675f8bfbf27e67f322baa0f9299846c69898e71cdabac70b8c19d82be5c3349bea9e0b3478fbe990e99bac4bbab7 + languageName: node + linkType: hard + +"verdaccio-htpasswd@npm:11.0.0-6-next.41": + version: 11.0.0-6-next.41 + resolution: "verdaccio-htpasswd@npm:11.0.0-6-next.41" + dependencies: + "@verdaccio/core": 6.0.0-6-next.71 + "@verdaccio/file-locking": 11.0.0-6-next.7 + apache-md5: 1.1.8 + bcryptjs: 2.4.3 + core-js: 3.30.2 + debug: 4.3.4 + http-errors: 2.0.0 + unix-crypt-td-js: 1.1.4 + checksum: 768083f3e7a54b504e41afd5c4d9e4057480a87b5434c96e924739086bc07812b6c115a57969008aae86493c2bd99a4ad829bd5d0705e254fc4668b5edf79a28 + languageName: node + linkType: hard + +"verdaccio@npm:^5.25.0": + version: 5.25.0 + resolution: "verdaccio@npm:5.25.0" + dependencies: + "@verdaccio/config": 6.0.0-6-next.71 + "@verdaccio/core": 6.0.0-6-next.71 + "@verdaccio/local-storage": 10.3.3 + "@verdaccio/logger-7": 6.0.0-6-next.16 + "@verdaccio/middleware": 6.0.0-6-next.50 + "@verdaccio/search": 6.0.0-6-next.2 + "@verdaccio/signature": 6.0.0-6-next.2 + "@verdaccio/streams": 10.2.1 + "@verdaccio/tarball": 11.0.0-6-next.40 + "@verdaccio/ui-theme": 6.0.0-6-next.71 + "@verdaccio/url": 11.0.0-6-next.37 + "@verdaccio/utils": 6.0.0-6-next.39 + JSONStream: 1.3.5 + async: 3.2.4 + body-parser: 1.20.2 + clipanion: 3.2.0 + compression: 1.7.4 + cookies: 0.8.0 + cors: 2.8.5 + debug: ^4.3.4 + envinfo: 7.8.1 + express: 4.18.2 + express-rate-limit: 5.5.1 + fast-safe-stringify: 2.1.1 + handlebars: 4.7.7 + js-yaml: 4.1.0 + jsonwebtoken: 9.0.0 + kleur: 4.1.5 + lodash: 4.17.21 + lru-cache: 7.18.3 + mime: 3.0.0 + mkdirp: 1.0.4 + mv: 2.1.1 + pkginfo: 0.4.1 + request: 2.88.2 + semver: 7.5.1 + validator: 13.9.0 + verdaccio-audit: 11.0.0-6-next.34 + verdaccio-htpasswd: 11.0.0-6-next.41 + dependenciesMeta: + "@verdaccio/types@11.0.0-6-next.24": + unplugged: true + bin: + verdaccio: bin/verdaccio + checksum: 8a69e41f1289cf7cc0adca90ed8b7eb0a59b3729cbe723e5cbbaf501413315b203dabe4352b8fed4ccaf684aff60d0df4d122060c2e8823389b39e58695815e6 + languageName: node + linkType: hard + +"verror@npm:1.10.0": + version: 1.10.0 + resolution: "verror@npm:1.10.0" + dependencies: + assert-plus: ^1.0.0 + core-util-is: 1.0.2 + extsprintf: ^1.2.0 + checksum: c431df0bedf2088b227a4e051e0ff4ca54df2c114096b0c01e1cbaadb021c30a04d7dd5b41ab277bcd51246ca135bf931d4c4c796ecae7a4fef6d744ecef36ea + languageName: node + linkType: hard + +"vscode-jsonrpc@npm:8.1.0, vscode-jsonrpc@npm:^8.0.2": + version: 8.1.0 + resolution: "vscode-jsonrpc@npm:8.1.0" + checksum: 8980037cc0014802e6ac1e5dfcff9a65e8292727096dfd23c92d2039c0c45de74a00d6ee06938cf1a671286dd8258a5f418cf048c26ad0fcb0c44f96c9e0f278 + languageName: node + linkType: hard + +"vscode-jsonrpc@npm:^6.0.0": + version: 6.0.0 + resolution: "vscode-jsonrpc@npm:6.0.0" + checksum: 3a67a56f287e8c449f2d9752eedf91e704dc7b9a326f47fb56ac07667631deb45ca52192e9bccb2ab108764e48409d70fa64b930d46fc3822f75270b111c5f53 + languageName: node + linkType: hard + +"vscode-languageserver-protocol@npm:^3.17.0": + version: 3.17.3 + resolution: "vscode-languageserver-protocol@npm:3.17.3" + dependencies: + vscode-jsonrpc: 8.1.0 + vscode-languageserver-types: 3.17.3 + checksum: ffea508b2efd7f4853f1cef5e5eac58672f0ae71a9ec275ad37a4a2a24cdc3ff023f941e759951aee01c79da3f3279f10e034f19d875f081eb387181241bd836 + languageName: node + linkType: hard + +"vscode-languageserver-types@npm:3.17.3": + version: 3.17.3 + resolution: "vscode-languageserver-types@npm:3.17.3" + checksum: fbc8221297261f659a6482875ff2a419dc9d55965dc53745797da569ff9f819cd832e6f2699017baadd946548bbfe212e3f6971f3d960f12dc0ee9c629dacc07 + languageName: node + linkType: hard + +"vscode-oniguruma@npm:^1.7.0": + version: 1.7.0 + resolution: "vscode-oniguruma@npm:1.7.0" + checksum: 53519d91d90593e6fb080260892e87d447e9b200c4964d766772b5053f5699066539d92100f77f1302c91e8fc5d9c772fbe40fe4c90f3d411a96d5a9b1e63f42 + languageName: node + linkType: hard + +"vscode-textmate@npm:^8.0.0": + version: 8.0.0 + resolution: "vscode-textmate@npm:8.0.0" + checksum: 127780dfea89559d70b8326df6ec344cfd701312dd7f3f591a718693812b7852c30b6715e3cfc8b3200a4e2515b4c96f0843c0eacc0a3020969b5de262c2a4bb + languageName: node + linkType: hard + +"vscode-ws-jsonrpc@npm:~1.0.2": + version: 1.0.2 + resolution: "vscode-ws-jsonrpc@npm:1.0.2" + dependencies: + vscode-jsonrpc: ^8.0.2 + checksum: eb2fdb5c96f124326505f06564dfc6584318b748fd6e39b4c0ba16a0d383d13ba0e9433596abdb841428dfc2a5501994c3206723d1cb38c6af5fcac1faf4be26 + languageName: node + linkType: hard + +"w3c-keyname@npm:^2.2.4": + version: 2.2.6 + resolution: "w3c-keyname@npm:2.2.6" + checksum: 59a31d23ca9953c01c99ed6695fee5b6ea36eb2412d76a21fe4302ab33a3f5cd96c006a763940b6115c3d042c16d3564eeee1156832217d028af0518098b3a42 + languageName: node + linkType: hard + +"w3c-xmlserializer@npm:^4.0.0": + version: 4.0.0 + resolution: "w3c-xmlserializer@npm:4.0.0" + dependencies: + xml-name-validator: ^4.0.0 + checksum: eba070e78deb408ae8defa4d36b429f084b2b47a4741c4a9be3f27a0a3d1845e277e3072b04391a138f7e43776842627d1334e448ff13ff90ad9fb1214ee7091 + languageName: node + linkType: hard + +"walker@npm:^1.0.8": + version: 1.0.8 + resolution: "walker@npm:1.0.8" + dependencies: + makeerror: 1.0.12 + checksum: ad7a257ea1e662e57ef2e018f97b3c02a7240ad5093c392186ce0bcf1f1a60bbadd520d073b9beb921ed99f64f065efb63dfc8eec689a80e569f93c1c5d5e16c + languageName: node + linkType: hard + +"watchpack@npm:^2.4.0": + version: 2.4.0 + resolution: "watchpack@npm:2.4.0" + dependencies: + glob-to-regexp: ^0.4.1 + graceful-fs: ^4.1.2 + checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 + languageName: node + linkType: hard + +"wcwidth@npm:^1.0.0, wcwidth@npm:^1.0.1": + version: 1.0.1 + resolution: "wcwidth@npm:1.0.1" + dependencies: + defaults: ^1.0.3 + checksum: 814e9d1ddcc9798f7377ffa448a5a3892232b9275ebb30a41b529607691c0491de47cba426e917a4d08ded3ee7e9ba2f3fe32e62ee3cd9c7d3bafb7754bd553c + languageName: node + linkType: hard + +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c + languageName: node + linkType: hard + +"webidl-conversions@npm:^6.1.0": + version: 6.1.0 + resolution: "webidl-conversions@npm:6.1.0" + checksum: 1f526507aa491f972a0c1409d07f8444e1d28778dfa269a9971f2e157182f3d496dc33296e4ed45b157fdb3bf535bb90c90bf10c50dcf1dd6caacb2a34cc84fb + languageName: node + linkType: hard + +"webidl-conversions@npm:^7.0.0": + version: 7.0.0 + resolution: "webidl-conversions@npm:7.0.0" + checksum: f05588567a2a76428515333eff87200fae6c83c3948a7482ebb109562971e77ef6dc49749afa58abb993391227c5697b3ecca52018793e0cb4620a48f10bd21b + languageName: node + linkType: hard + +"webpack-bundle-analyzer@npm:^4.8.0": + version: 4.8.0 + resolution: "webpack-bundle-analyzer@npm:4.8.0" + dependencies: + "@discoveryjs/json-ext": 0.5.7 + acorn: ^8.0.4 + acorn-walk: ^8.0.0 + chalk: ^4.1.0 + commander: ^7.2.0 + gzip-size: ^6.0.0 + lodash: ^4.17.20 + opener: ^1.5.2 + sirv: ^1.0.7 + ws: ^7.3.1 + bin: + webpack-bundle-analyzer: lib/bin/analyzer.js + checksum: acd86f68abb2bcb1a240043c6e2d8e53079499363afed94b96c0ec1abcc4fca2b7a7cbeeb5e13027d02a993c6ea8153194c69e7697faf47528bdaff1e2ce297e + languageName: node + linkType: hard + +"webpack-cli@npm:^5.0.1": + version: 5.0.1 + resolution: "webpack-cli@npm:5.0.1" + dependencies: + "@discoveryjs/json-ext": ^0.5.0 + "@webpack-cli/configtest": ^2.0.1 + "@webpack-cli/info": ^2.0.1 + "@webpack-cli/serve": ^2.0.1 + colorette: ^2.0.14 + commander: ^9.4.1 + cross-spawn: ^7.0.3 + envinfo: ^7.7.3 + fastest-levenshtein: ^1.0.12 + import-local: ^3.0.2 + interpret: ^3.1.1 + rechoir: ^0.8.0 + webpack-merge: ^5.7.3 + peerDependencies: + webpack: 5.x.x + peerDependenciesMeta: + "@webpack-cli/generators": + optional: true + webpack-bundle-analyzer: + optional: true + webpack-dev-server: + optional: true + bin: + webpack-cli: bin/cli.js + checksum: b1544eea669442e78c3dba9f79c0f8d0136759b8b2fe9cd32c0d410250fd719988ae037778ba88993215d44971169f2c268c0c934068be561711615f1951bd53 + languageName: node + linkType: hard + +"webpack-merge@npm:^5.7.3, webpack-merge@npm:^5.8.0": + version: 5.8.0 + resolution: "webpack-merge@npm:5.8.0" + dependencies: + clone-deep: ^4.0.1 + wildcard: ^2.0.0 + checksum: 88786ab91013f1bd2a683834ff381be81c245a4b0f63304a5103e90f6653f44dab496a0768287f8531761f8ad957d1f9f3ccb2cb55df0de1bd9ee343e079da26 + languageName: node + linkType: hard + +"webpack-sources@npm:^1.2.0": + version: 1.4.3 + resolution: "webpack-sources@npm:1.4.3" + dependencies: + source-list-map: ^2.0.0 + source-map: ~0.6.1 + checksum: 37463dad8d08114930f4bc4882a9602941f07c9f0efa9b6bc78738cd936275b990a596d801ef450d022bb005b109b9f451dd087db2f3c9baf53e8e22cf388f79 + languageName: node + linkType: hard + +"webpack-sources@npm:^3.0.0, webpack-sources@npm:^3.2.3": + version: 3.2.3 + resolution: "webpack-sources@npm:3.2.3" + checksum: 989e401b9fe3536529e2a99dac8c1bdc50e3a0a2c8669cbafad31271eadd994bc9405f88a3039cd2e29db5e6d9d0926ceb7a1a4e7409ece021fe79c37d9c4607 + languageName: node + linkType: hard + +"webpack@npm:^5.76.1": + version: 5.76.1 + resolution: "webpack@npm:5.76.1" + dependencies: + "@types/eslint-scope": ^3.7.3 + "@types/estree": ^0.0.51 + "@webassemblyjs/ast": 1.11.1 + "@webassemblyjs/wasm-edit": 1.11.1 + "@webassemblyjs/wasm-parser": 1.11.1 + acorn: ^8.7.1 + acorn-import-assertions: ^1.7.6 + browserslist: ^4.14.5 + chrome-trace-event: ^1.0.2 + enhanced-resolve: ^5.10.0 + es-module-lexer: ^0.9.0 + eslint-scope: 5.1.1 + events: ^3.2.0 + glob-to-regexp: ^0.4.1 + graceful-fs: ^4.2.9 + json-parse-even-better-errors: ^2.3.1 + loader-runner: ^4.2.0 + mime-types: ^2.1.27 + neo-async: ^2.6.2 + schema-utils: ^3.1.0 + tapable: ^2.1.1 + terser-webpack-plugin: ^5.1.3 + watchpack: ^2.4.0 + webpack-sources: ^3.2.3 + peerDependenciesMeta: + webpack-cli: + optional: true + bin: + webpack: bin/webpack.js + checksum: b01fe0bc2dbca0e10d290ddb0bf81e807a031de48028176e2b21afd696b4d3f25ab9accdad888ef4a1f7c7f4d41f13d5bf2395b7653fdf3e5e3dafa54e56dab2 + languageName: node + linkType: hard + +"whatwg-encoding@npm:^2.0.0": + version: 2.0.0 + resolution: "whatwg-encoding@npm:2.0.0" + dependencies: + iconv-lite: 0.6.3 + checksum: 7087810c410aa9b689cbd6af8773341a53cdc1f3aae2a882c163bd5522ec8ca4cdfc269aef417a5792f411807d5d77d50df4c24e3abb00bb60192858a40cc675 + languageName: node + linkType: hard + +"whatwg-fetch@npm:^3.0.0": + version: 3.6.2 + resolution: "whatwg-fetch@npm:3.6.2" + checksum: ee976b7249e7791edb0d0a62cd806b29006ad7ec3a3d89145921ad8c00a3a67e4be8f3fb3ec6bc7b58498724fd568d11aeeeea1f7827e7e1e5eae6c8a275afed + languageName: node + linkType: hard + +"whatwg-mimetype@npm:^2.3.0": + version: 2.3.0 + resolution: "whatwg-mimetype@npm:2.3.0" + checksum: 23eb885940bcbcca4ff841c40a78e9cbb893ec42743993a42bf7aed16085b048b44b06f3402018931687153550f9a32d259dfa524e4f03577ab898b6965e5383 + languageName: node + linkType: hard + +"whatwg-mimetype@npm:^3.0.0": + version: 3.0.0 + resolution: "whatwg-mimetype@npm:3.0.0" + checksum: ce08bbb36b6aaf64f3a84da89707e3e6a31e5ab1c1a2379fd68df79ba712a4ab090904f0b50e6693b0dafc8e6343a6157e40bf18fdffd26e513cf95ee2a59824 + languageName: node + linkType: hard + +"whatwg-url@npm:^11.0.0": + version: 11.0.0 + resolution: "whatwg-url@npm:11.0.0" + dependencies: + tr46: ^3.0.0 + webidl-conversions: ^7.0.0 + checksum: ed4826aaa57e66bb3488a4b25c9cd476c46ba96052747388b5801f137dd740b73fde91ad207d96baf9f17fbcc80fc1a477ad65181b5eb5fa718d27c69501d7af + languageName: node + linkType: hard + +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: ~0.0.3 + webidl-conversions: ^3.0.0 + checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c + languageName: node + linkType: hard + +"whatwg-url@npm:^8.0.0": + version: 8.7.0 + resolution: "whatwg-url@npm:8.7.0" + dependencies: + lodash: ^4.7.0 + tr46: ^2.1.0 + webidl-conversions: ^6.1.0 + checksum: a87abcc6cefcece5311eb642858c8fdb234e51ec74196bfacf8def2edae1bfbffdf6acb251646ed6301f8cee44262642d8769c707256125a91387e33f405dd1e + languageName: node + linkType: hard + +"which-boxed-primitive@npm:^1.0.2": + version: 1.0.2 + resolution: "which-boxed-primitive@npm:1.0.2" + dependencies: + is-bigint: ^1.0.1 + is-boolean-object: ^1.1.0 + is-number-object: ^1.0.4 + is-string: ^1.0.5 + is-symbol: ^1.0.3 + checksum: 53ce774c7379071729533922adcca47220228405e1895f26673bbd71bdf7fb09bee38c1d6399395927c6289476b5ae0629863427fd151491b71c4b6cb04f3a5e + languageName: node + linkType: hard + +"which-typed-array@npm:^1.1.9": + version: 1.1.9 + resolution: "which-typed-array@npm:1.1.9" + dependencies: + available-typed-arrays: ^1.0.5 + call-bind: ^1.0.2 + for-each: ^0.3.3 + gopd: ^1.0.1 + has-tostringtag: ^1.0.0 + is-typed-array: ^1.1.10 + checksum: fe0178ca44c57699ca2c0e657b64eaa8d2db2372a4e2851184f568f98c478ae3dc3fdb5f7e46c384487046b0cf9e23241423242b277e03e8ba3dabc7c84c98ef + languageName: node + linkType: hard + +"which@npm:^1.3.1": + version: 1.3.1 + resolution: "which@npm:1.3.1" + dependencies: + isexe: ^2.0.0 + bin: + which: ./bin/which + checksum: f2e185c6242244b8426c9df1510e86629192d93c1a986a7d2a591f2c24869e7ffd03d6dac07ca863b2e4c06f59a4cc9916c585b72ee9fa1aa609d0124df15e04 + languageName: node + linkType: hard + +"which@npm:^2.0.1, which@npm:^2.0.2": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: ^2.0.0 + bin: + node-which: ./bin/node-which + checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 + languageName: node + linkType: hard + +"which@npm:^3.0.0": + version: 3.0.1 + resolution: "which@npm:3.0.1" + dependencies: + isexe: ^2.0.0 + bin: + node-which: bin/which.js + checksum: adf720fe9d84be2d9190458194f814b5e9015ae4b88711b150f30d0f4d0b646544794b86f02c7ebeec1db2029bc3e83a7ff156f542d7521447e5496543e26890 + languageName: node + linkType: hard + +"wicked-good-xpath@npm:1.3.0": + version: 1.3.0 + resolution: "wicked-good-xpath@npm:1.3.0" + checksum: 1aa84bd57426aa07f95d7eca0b0410e841b8e7a35248c9404fa235eaf6a0932c811a96cbdc763c3df18ab76c7644fd8e807d8f185146154d3fc6baf554dcc7e3 + languageName: node + linkType: hard + +"wide-align@npm:^1.1.2, wide-align@npm:^1.1.5": + version: 1.1.5 + resolution: "wide-align@npm:1.1.5" + dependencies: + string-width: ^1.0.2 || 2 || 3 || 4 + checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 + languageName: node + linkType: hard + +"wildcard@npm:^2.0.0": + version: 2.0.0 + resolution: "wildcard@npm:2.0.0" + checksum: 1f4fe4c03dfc492777c60f795bbba597ac78794f1b650d68f398fbee9adb765367c516ebd4220889b6a81e9626e7228bbe0d66237abb311573c2ee1f4902a5ad + languageName: node + linkType: hard + +"word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": + version: 1.2.4 + resolution: "word-wrap@npm:1.2.4" + checksum: 8f1f2e0a397c0e074ca225ba9f67baa23f99293bc064e31355d426ae91b8b3f6b5f6c1fc9ae5e9141178bb362d563f55e62fd8d5c31f2a77e3ade56cb3e35bd1 + languageName: node + linkType: hard + +"wordwrap@npm:^1.0.0": + version: 1.0.0 + resolution: "wordwrap@npm:1.0.0" + checksum: 2a44b2788165d0a3de71fd517d4880a8e20ea3a82c080ce46e294f0b68b69a2e49cff5f99c600e275c698a90d12c5ea32aff06c311f0db2eb3f1201f3e7b2a04 + languageName: node + linkType: hard + +"worker-loader@npm:^3.0.2": + version: 3.0.8 + resolution: "worker-loader@npm:3.0.8" + dependencies: + loader-utils: ^2.0.0 + schema-utils: ^3.0.0 + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: 84f4a7eeb2a1d8b9704425837e017c91eedfae67ac89e0b866a2dcf283323c1dcabe0258196278b7d5fd0041392da895c8a0c59ddf3a94f1b2e003df68ddfec3 + languageName: node + linkType: hard + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" + dependencies: + ansi-styles: ^4.0.0 + string-width: ^4.1.0 + strip-ansi: ^6.0.0 + checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b + languageName: node + linkType: hard + +"wrap-ansi@npm:^8.0.1, wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: ^6.1.0 + string-width: ^5.0.1 + strip-ansi: ^7.0.1 + checksum: 371733296dc2d616900ce15a0049dca0ef67597d6394c57347ba334393599e800bab03c41d4d45221b6bc967b8c453ec3ae4749eff3894202d16800fdfe0e238 + languageName: node + linkType: hard + +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 + languageName: node + linkType: hard + +"write-file-atomic@npm:5.0.1, write-file-atomic@npm:^5.0.1": + version: 5.0.1 + resolution: "write-file-atomic@npm:5.0.1" + dependencies: + imurmurhash: ^0.1.4 + signal-exit: ^4.0.1 + checksum: 8dbb0e2512c2f72ccc20ccedab9986c7d02d04039ed6e8780c987dc4940b793339c50172a1008eed7747001bfacc0ca47562668a069a7506c46c77d7ba3926a9 + languageName: node + linkType: hard + +"write-file-atomic@npm:^2.4.2": + version: 2.4.3 + resolution: "write-file-atomic@npm:2.4.3" + dependencies: + graceful-fs: ^4.1.11 + imurmurhash: ^0.1.4 + signal-exit: ^3.0.2 + checksum: 2db81f92ae974fd87ab4a5e7932feacaca626679a7c98fcc73ad8fcea5a1950eab32fa831f79e9391ac99b562ca091ad49be37a79045bd65f595efbb8f4596ae + languageName: node + linkType: hard + +"write-file-atomic@npm:^4.0.2": + version: 4.0.2 + resolution: "write-file-atomic@npm:4.0.2" + dependencies: + imurmurhash: ^0.1.4 + signal-exit: ^3.0.7 + checksum: 5da60bd4eeeb935eec97ead3df6e28e5917a6bd317478e4a85a5285e8480b8ed96032bbcc6ecd07b236142a24f3ca871c924ec4a6575e623ec1b11bf8c1c253c + languageName: node + linkType: hard + +"write-json-file@npm:^3.2.0": + version: 3.2.0 + resolution: "write-json-file@npm:3.2.0" + dependencies: + detect-indent: ^5.0.0 + graceful-fs: ^4.1.15 + make-dir: ^2.1.0 + pify: ^4.0.1 + sort-keys: ^2.0.0 + write-file-atomic: ^2.4.2 + checksum: 2b97ce2027d53c28a33e4a8e7b0d565faf785988b3776f9e0c68d36477c1fb12639fd0d70877d92a861820707966c62ea9c5f7a36a165d615fd47ca8e24c8371 + languageName: node + linkType: hard + +"write-pkg@npm:4.0.0": + version: 4.0.0 + resolution: "write-pkg@npm:4.0.0" + dependencies: + sort-keys: ^2.0.0 + type-fest: ^0.4.1 + write-json-file: ^3.2.0 + checksum: 7864d44370f42a6761f6898d07ee2818c7a2faad45116580cf779f3adaf94e4bea5557612533a6c421c32323253ecb63b50615094960a637aeaef5df0fd2d6cd + languageName: node + linkType: hard + +"ws@npm:8.12.0, ws@npm:^8.11.0": + version: 8.12.0 + resolution: "ws@npm:8.12.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 818ff3f8749c172a95a114cceb8b89cedd27e43a82d65c7ad0f7882b1e96a2ee6709e3746a903c3fa88beec0c8bae9a9fcd75f20858b32a166dfb7519316a5d7 + languageName: node + linkType: hard + +"ws@npm:^7.3.1": + version: 7.5.9 + resolution: "ws@npm:7.5.9" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: c3c100a181b731f40b7f2fddf004aa023f79d64f489706a28bc23ff88e87f6a64b3c6651fbec3a84a53960b75159574d7a7385709847a62ddb7ad6af76f49138 + languageName: node + linkType: hard + +"xml-name-validator@npm:^4.0.0": + version: 4.0.0 + resolution: "xml-name-validator@npm:4.0.0" + checksum: af100b79c29804f05fa35aa3683e29a321db9b9685d5e5febda3fa1e40f13f85abc40f45a6b2bf7bee33f68a1dc5e8eaef4cec100a304a9db565e6061d4cb5ad + languageName: node + linkType: hard + +"xml@npm:^1.0.1": + version: 1.0.1 + resolution: "xml@npm:1.0.1" + checksum: 11b5545ef3f8fec3fa29ce251f50ad7b6c97c103ed4d851306ec23366f5fa4699dd6a942262df52313a0cd1840ab26256da253c023bad3309d8ce46fe6020ca0 + languageName: node + linkType: hard + +"xmlchars@npm:^2.2.0": + version: 2.2.0 + resolution: "xmlchars@npm:2.2.0" + checksum: 8c70ac94070ccca03f47a81fcce3b271bd1f37a591bf5424e787ae313fcb9c212f5f6786e1fa82076a2c632c0141552babcd85698c437506dfa6ae2d58723062 + languageName: node + linkType: hard + +"xmldom-sre@npm:0.1.31": + version: 0.1.31 + resolution: "xmldom-sre@npm:0.1.31" + checksum: dbd101600a64c1640b06fb2b5c626ce6d909fd40c966fcae84a2b64c708fe466630766173b5760e0275db2a2c542e048b14a2a6568feece2c315f0cd22a2f642 + languageName: node + linkType: hard + +"xtend@npm:^4.0.1, xtend@npm:~4.0.1": + version: 4.0.2 + resolution: "xtend@npm:4.0.2" + checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a + languageName: node + linkType: hard + +"xterm-addon-canvas@npm:~0.3.0": + version: 0.3.0 + resolution: "xterm-addon-canvas@npm:0.3.0" + peerDependencies: + xterm: ^5.0.0 + checksum: 21eabd28a2718e775399f27e21922ec4e22528576ae88278ef39c68239119e4576eecd59cf0f1c76dfcbea0f82b779f8dbaf4ce38e04e648844c33ac7632d333 + languageName: node + linkType: hard + +"xterm-addon-fit@npm:~0.7.0": + version: 0.7.0 + resolution: "xterm-addon-fit@npm:0.7.0" + peerDependencies: + xterm: ^5.0.0 + checksum: 512d41f80d6f9427ba02dab4e6fd642e94775a9cf7ef72ae4b55eab2a36856b5c67069bfc66b4af412fdce29a0842f9c6382af3672f0b514c4352dfd47defe8f + languageName: node + linkType: hard + +"xterm-addon-web-links@npm:~0.8.0": + version: 0.8.0 + resolution: "xterm-addon-web-links@npm:0.8.0" + peerDependencies: + xterm: ^5.0.0 + checksum: fe07572adfaa84ceeb961db3ae577aeb2342ea5dcd4948170d1b733ae8045693fab8808f9c63cc43a532b033ae95e63e62ac14bc2e34def764e68f6362ccae2b + languageName: node + linkType: hard + +"xterm-addon-webgl@npm:~0.14.0": + version: 0.14.0 + resolution: "xterm-addon-webgl@npm:0.14.0" + peerDependencies: + xterm: ^5.0.0 + checksum: 05f144c920660ad8122aa13564612b1ce71b92ba8f74b3387db3e39b616437659da36b7edf3aefe5900c59956cd6ca1272a0892248df751c8899a202befe019c + languageName: node + linkType: hard + +"xterm@npm:~5.1.0": + version: 5.1.0 + resolution: "xterm@npm:5.1.0" + checksum: cbacbc9dc1bbcf21dabecff46856b43f2d5854b42c1bec4ea03a5720000f2a88d79b0da45b6c38213d6607474a1fbe66d5ff25fa120b7e9e60eeed964dd840a1 + languageName: node + linkType: hard + +"y-protocols@npm:^1.0.5": + version: 1.0.5 + resolution: "y-protocols@npm:1.0.5" + dependencies: + lib0: ^0.2.42 + checksum: d19404a4ebafcf3761c28b881abe8c32ab6e457db0e5ffc7dbb749cbc2c3bb98e003a43f3e8eba7f245b2698c76f2c4cdd1c2db869f8ec0c6ef94736d9a88652 + languageName: node + linkType: hard + +"y18n@npm:^5.0.5": + version: 5.0.8 + resolution: "y18n@npm:5.0.8" + checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30 + languageName: node + linkType: hard + +"yallist@npm:*, yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 + languageName: node + linkType: hard + +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d + languageName: node + linkType: hard + +"yargs-parser@npm:20.2.4": + version: 20.2.4 + resolution: "yargs-parser@npm:20.2.4" + checksum: d251998a374b2743a20271c2fd752b9fbef24eb881d53a3b99a7caa5e8227fcafd9abf1f345ac5de46435821be25ec12189a11030c12ee6481fef6863ed8b924 + languageName: node + linkType: hard + +"yargs-parser@npm:21.1.1, yargs-parser@npm:^21.0.1, yargs-parser@npm:^21.1.1": + version: 21.1.1 + resolution: "yargs-parser@npm:21.1.1" + checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c + languageName: node + linkType: hard + +"yargs-parser@npm:^20.2.2, yargs-parser@npm:^20.2.3, yargs-parser@npm:^20.2.9": + version: 20.2.9 + resolution: "yargs-parser@npm:20.2.9" + checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3 + languageName: node + linkType: hard + +"yargs@npm:16.2.0, yargs@npm:^16.2.0": + version: 16.2.0 + resolution: "yargs@npm:16.2.0" + dependencies: + cliui: ^7.0.2 + escalade: ^3.1.1 + get-caller-file: ^2.0.5 + require-directory: ^2.1.1 + string-width: ^4.2.0 + y18n: ^5.0.5 + yargs-parser: ^20.2.2 + checksum: b14afbb51e3251a204d81937c86a7e9d4bdbf9a2bcee38226c900d00f522969ab675703bee2a6f99f8e20103f608382936034e64d921b74df82b63c07c5e8f59 + languageName: node + linkType: hard + +"yargs@npm:^17.3.1, yargs@npm:^17.6.2, yargs@npm:~17.6.2": + version: 17.6.2 + resolution: "yargs@npm:17.6.2" + dependencies: + cliui: ^8.0.1 + escalade: ^3.1.1 + get-caller-file: ^2.0.5 + require-directory: ^2.1.1 + string-width: ^4.2.3 + y18n: ^5.0.5 + yargs-parser: ^21.1.1 + checksum: 47da1b0d854fa16d45a3ded57b716b013b2179022352a5f7467409da5a04a1eef5b3b3d97a2dfc13e8bbe5f2ffc0afe3bc6a4a72f8254e60f5a4bd7947138643 + languageName: node + linkType: hard + +"yjs@npm:^13.5.40": + version: 13.5.49 + resolution: "yjs@npm:13.5.49" + dependencies: + lib0: ^0.2.49 + checksum: d5e0ec9ce055cff0abf6335106ee6b946948995cf29ae2a1702070e1d4418e62bdf1a73348a6f552c467181a8a5bb4c7d72f1acaaacd27eac5977014ffd2a210 + languageName: node + linkType: hard + +"yocto-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "yocto-queue@npm:0.1.0" + checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 + languageName: node + linkType: hard + +"yup@npm:0.32.11": + version: 0.32.11 + resolution: "yup@npm:0.32.11" + dependencies: + "@babel/runtime": ^7.15.4 + "@types/lodash": ^4.14.175 + lodash: ^4.17.21 + lodash-es: ^4.17.21 + nanoclone: ^0.2.1 + property-expr: ^2.0.4 + toposort: ^2.0.2 + checksum: 43a16786b47cc910fed4891cebdd89df6d6e31702e9462e8f969c73eac88551ce750732608012201ea6b93802c8847cb0aa27b5d57370640f4ecf30f9f97d4b0 + languageName: node + linkType: hard